From 9fbc9105a62e5ca309d5152407dea0db86cc1709 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 8 Oct 2018 15:47:22 -0700 Subject: Update tests --- .../tests/ChannelTests/ChannelPoolTest.m | 164 ++++ src/objective-c/tests/ChannelTests/ChannelTests.m | 93 +++ src/objective-c/tests/ChannelTests/Info.plist | 22 + src/objective-c/tests/GRPCClientTests.m | 291 ++++++- src/objective-c/tests/InteropTests.h | 21 + src/objective-c/tests/InteropTests.m | 201 +++++ .../tests/InteropTestsCallOptions/Info.plist | 22 + .../InteropTestsCallOptions.m | 116 +++ src/objective-c/tests/InteropTestsLocalCleartext.m | 12 + src/objective-c/tests/InteropTestsLocalSSL.m | 16 + .../tests/InteropTestsMultipleChannels/Info.plist | 22 + .../InteropTestsMultipleChannels.m | 259 +++++++ src/objective-c/tests/InteropTestsRemote.m | 18 + src/objective-c/tests/Podfile | 10 +- .../tests/Tests.xcodeproj/project.pbxproj | 832 ++++++++++++++++++++- .../xcshareddata/xcschemes/ChannelTests.xcscheme | 92 +++ .../xcschemes/InteropTestsCallOptions.xcscheme | 56 ++ .../xcschemes/InteropTestsLocalCleartext.xcscheme | 8 - .../InteropTestsMultipleChannels.xcscheme | 56 ++ .../xcschemes/InteropTestsRemote.xcscheme | 2 - src/objective-c/tests/run_tests.sh | 10 + 21 files changed, 2305 insertions(+), 18 deletions(-) create mode 100644 src/objective-c/tests/ChannelTests/ChannelPoolTest.m create mode 100644 src/objective-c/tests/ChannelTests/ChannelTests.m create mode 100644 src/objective-c/tests/ChannelTests/Info.plist create mode 100644 src/objective-c/tests/InteropTestsCallOptions/Info.plist create mode 100644 src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m create mode 100644 src/objective-c/tests/InteropTestsMultipleChannels/Info.plist create mode 100644 src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m create mode 100644 src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme create mode 100644 src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme create mode 100644 src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m new file mode 100644 index 0000000000..3b6b10b1a5 --- /dev/null +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -0,0 +1,164 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import "../../GRPCClient/private/GRPCChannel.h" +#import "../../GRPCClient/private/GRPCChannelPool.h" + +#define TEST_TIMEOUT 32 + +NSString *kDummyHost = @"dummy.host"; + +@interface ChannelPoolTest : XCTestCase + +@end + +@implementation ChannelPoolTest + ++ (void)setUp { + grpc_init(); +} + +- (void)testCreateChannel { + NSString *kDummyHost = @"dummy.host"; + GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; + options1.transportType = GRPCTransportTypeInsecure; + GRPCCallOptions *options2 = [options1 copy]; + GRPCChannelConfiguration *config1 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; + GRPCChannelConfiguration *config2 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initWithChannelDestroyDelay:1]; + + __weak XCTestExpectation *expectCreateChannel = + [self expectationWithDescription:@"Create first channel"]; + GRPCChannel *channel1 = + [pool channelWithConfiguration:config1 + createChannel:^{ + [expectCreateChannel fulfill]; + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; + GRPCChannel *channel2 = [pool channelWithConfiguration:config2 + createChannel:^{ + XCTFail(@"Should not create a second channel."); + return (GRPCChannel *)nil; + }]; + XCTAssertEqual(channel1, channel2); +} + +- (void)testChannelTimeout { + NSTimeInterval kChannelDestroyDelay = 1.0; + GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; + options1.transportType = GRPCTransportTypeInsecure; + GRPCChannelConfiguration *config1 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; + GRPCChannelPool *pool = + [[GRPCChannelPool alloc] initWithChannelDestroyDelay:kChannelDestroyDelay]; + GRPCChannel *channel1 = + [pool channelWithConfiguration:config1 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + [pool unrefChannelWithConfiguration:config1]; + __weak XCTestExpectation *expectTimerDone = [self expectationWithDescription:@"Timer elapse."]; + NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:kChannelDestroyDelay + 1 + repeats:NO + block:^(NSTimer *_Nonnull timer) { + [expectTimerDone fulfill]; + }]; + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; + timer = nil; + GRPCChannel *channel2 = + [pool channelWithConfiguration:config1 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + XCTAssertNotEqual(channel1, channel2); +} + +- (void)testChannelTimeoutCancel { + NSTimeInterval kChannelDestroyDelay = 3.0; + GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; + options1.transportType = GRPCTransportTypeInsecure; + GRPCChannelConfiguration *config1 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; + GRPCChannelPool *pool = + [[GRPCChannelPool alloc] initWithChannelDestroyDelay:kChannelDestroyDelay]; + GRPCChannel *channel1 = + [pool channelWithConfiguration:config1 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + [channel1 unmanagedCallUnref]; + sleep(1); + GRPCChannel *channel2 = + [pool channelWithConfiguration:config1 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + XCTAssertEqual(channel1, channel2); + sleep((int)kChannelDestroyDelay + 2); + GRPCChannel *channel3 = + [pool channelWithConfiguration:config1 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + XCTAssertEqual(channel1, channel3); +} + +- (void)testClearChannels { + GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; + options1.transportType = GRPCTransportTypeInsecure; + GRPCMutableCallOptions *options2 = [[GRPCMutableCallOptions alloc] init]; + options2.transportType = GRPCTransportTypeDefault; + GRPCChannelConfiguration *config1 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; + GRPCChannelConfiguration *config2 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initWithChannelDestroyDelay:1]; + + GRPCChannel *channel1 = + [pool channelWithConfiguration:config1 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + GRPCChannel *channel2 = + [pool channelWithConfiguration:config2 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config2]; + }]; + XCTAssertNotEqual(channel1, channel2); + + [pool clear]; + GRPCChannel *channel3 = + [pool channelWithConfiguration:config1 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config1]; + }]; + GRPCChannel *channel4 = + [pool channelWithConfiguration:config2 + createChannel:^{ + return [GRPCChannel createChannelWithConfiguration:config2]; + }]; + XCTAssertNotEqual(channel1, channel3); + XCTAssertNotEqual(channel2, channel4); +} + +@end diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m new file mode 100644 index 0000000000..0a8b7ae6ee --- /dev/null +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -0,0 +1,93 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import "../../GRPCClient/GRPCCallOptions.h" +#import "../../GRPCClient/private/GRPCChannel.h" + +@interface ChannelTests : XCTestCase + +@end + +@implementation ChannelTests + ++ (void)setUp { + grpc_init(); +} + +- (void)testSameConfiguration { + NSString *host = @"grpc-test.sandbox.googleapis.com"; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.userAgentPrefix = @"TestUAPrefix"; + NSMutableDictionary *args = [NSMutableDictionary new]; + args[@"abc"] = @"xyz"; + options.additionalChannelArgs = [args copy]; + GRPCChannel *channel1 = [GRPCChannel channelWithHost:host callOptions:options]; + GRPCChannel *channel2 = [GRPCChannel channelWithHost:host callOptions:options]; + XCTAssertEqual(channel1, channel2); + GRPCMutableCallOptions *options2 = [options mutableCopy]; + options2.additionalChannelArgs = [args copy]; + GRPCChannel *channel3 = [GRPCChannel channelWithHost:host callOptions:options2]; + XCTAssertEqual(channel1, channel3); +} + +- (void)testDifferentHost { + NSString *host1 = @"grpc-test.sandbox.googleapis.com"; + NSString *host2 = @"grpc-test2.sandbox.googleapis.com"; + NSString *host3 = @"http://grpc-test.sandbox.googleapis.com"; + NSString *host4 = @"dns://grpc-test.sandbox.googleapis.com"; + NSString *host5 = @"grpc-test.sandbox.googleapis.com:80"; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.userAgentPrefix = @"TestUAPrefix"; + NSMutableDictionary *args = [NSMutableDictionary new]; + args[@"abc"] = @"xyz"; + options.additionalChannelArgs = [args copy]; + GRPCChannel *channel1 = [GRPCChannel channelWithHost:host1 callOptions:options]; + GRPCChannel *channel2 = [GRPCChannel channelWithHost:host2 callOptions:options]; + GRPCChannel *channel3 = [GRPCChannel channelWithHost:host3 callOptions:options]; + GRPCChannel *channel4 = [GRPCChannel channelWithHost:host4 callOptions:options]; + GRPCChannel *channel5 = [GRPCChannel channelWithHost:host5 callOptions:options]; + XCTAssertNotEqual(channel1, channel2); + XCTAssertNotEqual(channel1, channel3); + XCTAssertNotEqual(channel1, channel4); + XCTAssertNotEqual(channel1, channel5); +} + +- (void)testDifferentChannelParameters { + NSString *host = @"grpc-test.sandbox.googleapis.com"; + GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; + options1.transportType = GRPCTransportTypeDefault; + NSMutableDictionary *args = [NSMutableDictionary new]; + args[@"abc"] = @"xyz"; + options1.additionalChannelArgs = [args copy]; + GRPCMutableCallOptions *options2 = [[GRPCMutableCallOptions alloc] init]; + options2.transportType = GRPCTransportTypeInsecure; + options2.additionalChannelArgs = [args copy]; + GRPCMutableCallOptions *options3 = [[GRPCMutableCallOptions alloc] init]; + options3.transportType = GRPCTransportTypeDefault; + args[@"def"] = @"uvw"; + options3.additionalChannelArgs = [args copy]; + GRPCChannel *channel1 = [GRPCChannel channelWithHost:host callOptions:options1]; + GRPCChannel *channel2 = [GRPCChannel channelWithHost:host callOptions:options2]; + GRPCChannel *channel3 = [GRPCChannel channelWithHost:host callOptions:options3]; + XCTAssertNotEqual(channel1, channel2); + XCTAssertNotEqual(channel1, channel3); +} + +@end diff --git a/src/objective-c/tests/ChannelTests/Info.plist b/src/objective-c/tests/ChannelTests/Info.plist new file mode 100644 index 0000000000..6c40a6cd0c --- /dev/null +++ b/src/objective-c/tests/ChannelTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index a0de8ba899..bad22d30cb 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -86,6 +86,58 @@ static GRPCProtoMethod *kFullDuplexCallMethod; @end +// Convenience class to use blocks as callbacks +@interface ClientTestsBlockCallbacks : NSObject + +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback; + +@end + +@implementation ClientTestsBlockCallbacks { + void (^_initialMetadataCallback)(NSDictionary *); + void (^_messageCallback)(id); + void (^_closeCallback)(NSDictionary *, NSError *); + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback { + if ((self = [super init])) { + _initialMetadataCallback = initialMetadataCallback; + _messageCallback = messageCallback; + _closeCallback = closeCallback; + _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { + if (_initialMetadataCallback) { + _initialMetadataCallback(initialMetadata); + } +} + +- (void)receivedMessage:(id)message { + if (_messageCallback) { + _messageCallback(message); + } +} + +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { + if (_closeCallback) { + _closeCallback(trailingMetadata, error); + } +} + +- (dispatch_queue_t)dispatchQueue { + return _dispatchQueue; +} + +@end + #pragma mark Tests /** @@ -237,6 +289,55 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testMetadataWithV2API { + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.fillUsername = YES; + request.fillOauthScope = YES; + + GRPCRequestOptions *callRequest = + [[GRPCRequestOptions alloc] initWithHost:(NSString *)kRemoteSSLHost + path:kUnaryCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + __block NSDictionary *init_md; + __block NSDictionary *trailing_md; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.oauth2AccessToken = @"bogusToken"; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:callRequest + handler:[[ClientTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) { + init_md = initialMetadata; + } + messageCallback:^(id message) { + XCTFail(@"Received unexpected response."); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + trailing_md = trailingMetadata; + if (error) { + XCTAssertEqual(error.code, 16, + @"Finished with unexpected error: %@", error); + XCTAssertEqualObjects(init_md, + error.userInfo[kGRPCHeadersKey]); + XCTAssertEqualObjects(trailing_md, + error.userInfo[kGRPCTrailersKey]); + NSString *challengeHeader = init_md[@"www-authenticate"]; + XCTAssertGreaterThan(challengeHeader.length, 0, + @"No challenge in response headers %@", + init_md); + [expectation fulfill]; + } + }] + callOptions:options]; + + [call start]; + [call writeWithData:[request data]]; + [call finish]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testResponseMetadataKVO { __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; @@ -329,6 +430,77 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testUserAgentPrefixWithV2API { + __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; + __weak XCTestExpectation *recvInitialMd = + [self expectationWithDescription:@"Did not receive initial md."]; + + GRPCRequestOptions *request = [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kEmptyCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + NSDictionary *headers = + [NSDictionary dictionaryWithObjectsAndKeys:@"", @"x-grpc-test-echo-useragent", nil]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = GRPCTransportTypeInsecure; + options.userAgentPrefix = @"Foo"; + options.initialMetadata = headers; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:request + handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^( + NSDictionary *initialMetadata) { + NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"]; + // Test the regex is correct + NSString *expectedUserAgent = @"Foo grpc-objc/"; + expectedUserAgent = + [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"]; + expectedUserAgent = + [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; + expectedUserAgent = + [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "]; + expectedUserAgent = [expectedUserAgent + stringByAppendingString:[NSString + stringWithUTF8String:grpc_g_stands_for()]]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"]; + XCTAssertEqualObjects(userAgent, expectedUserAgent); + + NSError *error = nil; + // Change in format of user-agent field in a direction that does not match + // the regex will likely cause problem for certain gRPC users. For details, + // refer to internal doc https://goo.gl/c2diBc + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern: + @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" + options:0 + error:&error]; + + NSString *customUserAgent = [regex + stringByReplacingMatchesInString:userAgent + options:0 + range:NSMakeRange(0, [userAgent length]) + withTemplate:@""]; + XCTAssertEqualObjects(customUserAgent, @"Foo"); + [recvInitialMd fulfill]; + } + messageCallback:^(id message) { + XCTAssertNotNil(message); + XCTAssertEqual([message length], 0, + @"Non-empty response received: %@", message); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + if (error) { + XCTFail(@"Finished with unexpected error: %@", error); + } else { + [completion fulfill]; + } + }] + callOptions:options]; + [call writeWithData:[NSData data]]; + [call start]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testTrailers { __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; @@ -420,6 +592,52 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testIdempotentProtoRPCWithV2API { + __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."]; + __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.responseSize = 100; + request.fillUsername = YES; + request.fillOauthScope = YES; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kUnaryCallMethod.HTTPPath + safety:GRPCCallSafetyIdempotentRequest]; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = GRPCTransportTypeInsecure; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + NSData *data = (NSData *)message; + XCTAssertNotNil(data, @"nil value received as response."); + XCTAssertGreaterThan(data.length, 0, + @"Empty response received."); + RMTSimpleResponse *responseProto = + [RMTSimpleResponse parseFromData:data error:NULL]; + // We expect empty strings, not nil: + XCTAssertNotNil(responseProto.username, + @"Response's username is nil."); + XCTAssertNotNil(responseProto.oauthScope, + @"Response's OAuth scope is nil."); + [response fulfill]; + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", + error); + [completion fulfill]; + }] + callOptions:options]; + + [call start]; + [call writeWithData:[request data]]; + [call finish]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testAlternateDispatchQueue { const int32_t kPayloadSize = 100; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -509,6 +727,38 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testTimeoutWithV2API { + __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.timeout = 0.001; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kFullDuplexCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + handler: + [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id data) { + XCTFail( + @"Failure: response received; Expect: no response received."); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNotNil(error, + @"Failure: no error received; Expect: receive " + @"deadline exceeded."); + XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded); + [completion fulfill]; + }] + callOptions:options]; + + [call start]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (int)findFreePort { struct sockaddr_in addr; unsigned int addr_len = sizeof(addr); @@ -580,15 +830,52 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testTimeoutBackoffWithOptionsWithTimeout:(double)timeout Backoff:(double)backoff { + const double maxConnectTime = timeout > backoff ? timeout : backoff; + const double kMargin = 0.1; + + __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; + NSString *const kDummyAddress = [NSString stringWithFormat:@"8.8.8.8:1"]; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kDummyAddress path:@"" safety:GRPCCallSafetyDefault]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.connectMinTimeout = timeout; + options.connectInitialBackoff = backoff; + options.connectMaxBackoff = 0; + + NSDate *startTime = [NSDate date]; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id data) { + XCTFail(@"Received message. Should not reach here."); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNotNil(error, + @"Finished with no error; expecting error"); + XCTAssertLessThan( + [[NSDate date] timeIntervalSinceDate:startTime], + maxConnectTime + kMargin); + [completion fulfill]; + }] + callOptions:options]; + + [call start]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + // The numbers of the following three tests are selected to be smaller than the default values of // initial backoff (1s) and min_connect_timeout (20s), so that if they fail we know the default // values fail to be overridden by the channel args. -- (void)testTimeoutBackoff2 { +- (void)testTimeoutBackoff1 { [self testTimeoutBackoffWithTimeout:0.7 Backoff:0.3]; + [self testTimeoutBackoffWithOptionsWithTimeout:0.7 Backoff:0.4]; } -- (void)testTimeoutBackoff3 { +- (void)testTimeoutBackoff2 { [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.7]; + [self testTimeoutBackoffWithOptionsWithTimeout:0.3 Backoff:0.8]; } - (void)testErrorDebugInformation { diff --git a/src/objective-c/tests/InteropTests.h b/src/objective-c/tests/InteropTests.h index 039d92a8d3..e223839d3a 100644 --- a/src/objective-c/tests/InteropTests.h +++ b/src/objective-c/tests/InteropTests.h @@ -18,6 +18,8 @@ #import +#import + /** * Implements tests as described here: * https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md @@ -38,4 +40,23 @@ * remote servers enconde responses with different overhead (?), so this is defined per-subclass. */ - (int32_t)encodingOverhead; + +/** + * The type of transport to be used. The base implementation returns default. Subclasses should + * override to appropriate settings. + */ ++ (GRPCTransportType)transportType; + +/** + * The root certificates to be used. The base implementation returns nil. Subclasses should override + * to appropriate settings. + */ ++ (NSString *)pemRootCert; + +/** + * The root certificates to be used. The base implementation returns nil. Subclasses should override + * to appropriate settings. + */ ++ (NSString *)hostNameOverride; + @end diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 9d79606881..54af7036c3 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -74,6 +74,58 @@ BOOL isRemoteInteropTest(NSString *host) { return [host isEqualToString:@"grpc-test.sandbox.googleapis.com"]; } +// Convenience class to use blocks as callbacks +@interface InteropTestsBlockCallbacks : NSObject + +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback; + +@end + +@implementation InteropTestsBlockCallbacks { + void (^_initialMetadataCallback)(NSDictionary *); + void (^_messageCallback)(id); + void (^_closeCallback)(NSDictionary *, NSError *); + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback { + if ((self = [super init])) { + _initialMetadataCallback = initialMetadataCallback; + _messageCallback = messageCallback; + _closeCallback = closeCallback; + _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { + if (_initialMetadataCallback) { + _initialMetadataCallback(initialMetadata); + } +} + +- (void)receivedMessage:(id)message { + if (_messageCallback) { + _messageCallback(message); + } +} + +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { + if (_closeCallback) { + _closeCallback(trailingMetadata, error); + } +} + +- (dispatch_queue_t)dispatchQueue { + return _dispatchQueue; +} + +@end + #pragma mark Tests @implementation InteropTests { @@ -91,6 +143,18 @@ BOOL isRemoteInteropTest(NSString *host) { return 0; } ++ (GRPCTransportType)transportType { + return GRPCTransportTypeDefault; +} + ++ (NSString *)pemRootCert { + return nil; +} + ++ (NSString *)hostNameOverride { + return nil; +} + + (void)setUp { NSLog(@"InteropTest Started, class: %@", [[self class] description]); #ifdef GRPC_COMPILE_WITH_CRONET @@ -131,6 +195,33 @@ BOOL isRemoteInteropTest(NSString *host) { [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testEmptyUnaryRPCWithV2API { + XCTAssertNotNil(self.class.host); + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"]; + + GPBEmpty *request = [GPBEmpty message]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = self.class.transportType; + options.pemRootCert = self.class.pemRootCert; + options.hostNameOverride = self.class.hostNameOverride; + + [_service + emptyCallWithMessage:request + responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + if (message) { + id expectedResponse = [GPBEmpty message]; + XCTAssertEqualObjects(message, expectedResponse); + [expectation fulfill]; + } + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNil(error, @"Unexpected error: %@", error); + }] + callOptions:options]; + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testLargeUnaryRPC { XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"]; @@ -380,6 +471,57 @@ BOOL isRemoteInteropTest(NSString *host) { [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testPingPongRPCWithV2API { + XCTAssertNotNil(self.class.host); + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"]; + + NSArray *requests = @[ @27182, @8, @1828, @45904 ]; + NSArray *responses = @[ @31415, @9, @2653, @58979 ]; + + __block int index = 0; + + id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] + requestedResponseSize:responses[index]]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = self.class.transportType; + options.pemRootCert = self.class.pemRootCert; + options.hostNameOverride = self.class.hostNameOverride; + + __block GRPCStreamingProtoCall *call = [_service + fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + XCTAssertLessThan(index, 4, + @"More than 4 responses received."); + id expected = [RMTStreamingOutputCallResponse + messageWithPayloadSize:responses[index]]; + XCTAssertEqualObjects(message, expected); + index += 1; + if (index < 4) { + id request = [RMTStreamingOutputCallRequest + messageWithPayloadSize:requests[index] + requestedResponseSize:responses[index]]; + [call writeWithMessage:request]; + } else { + [call finish]; + } + } + closeCallback:^(NSDictionary *trailingMetadata, + NSError *error) { + XCTAssertNil(error, + @"Finished with unexpected error: %@", + error); + XCTAssertEqual(index, 4, + @"Received %i responses instead of 4.", + index); + [expectation fulfill]; + }] + callOptions:options]; + [call writeWithMessage:request]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testEmptyStreamRPC { XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"]; @@ -418,6 +560,28 @@ BOOL isRemoteInteropTest(NSString *host) { [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testCancelAfterBeginRPCWithV2API { + XCTAssertNotNil(self.class.host); + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBegin"]; + + // A buffered pipe to which we never write any value acts as a writer that just hangs. + __block GRPCStreamingProtoCall *call = [_service + streamingInputCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + XCTFail(@"Not expected to receive message"); + } + closeCallback:^(NSDictionary *trailingMetadata, + NSError *error) { + XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); + [expectation fulfill]; + }] + callOptions:nil]; + [call cancel]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testCancelAfterFirstResponseRPC { XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = @@ -454,6 +618,43 @@ BOOL isRemoteInteropTest(NSString *host) { [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testCancelAfterFirstResponseRPCWithV2API { + XCTAssertNotNil(self.class.host); + __weak XCTestExpectation *completionExpectation = + [self expectationWithDescription:@"Call completed."]; + __weak XCTestExpectation *responseExpectation = + [self expectationWithDescription:@"Received response."]; + + __block BOOL receivedResponse = NO; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = self.class.transportType; + options.pemRootCert = self.class.pemRootCert; + options.hostNameOverride = self.class.hostNameOverride; + + id request = + [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 requestedResponseSize:@31415]; + + __block GRPCStreamingProtoCall *call = [_service + fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + XCTAssertFalse(receivedResponse); + receivedResponse = YES; + [call cancel]; + [responseExpectation fulfill]; + } + closeCallback:^(NSDictionary *trailingMetadata, + NSError *error) { + XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); + [completionExpectation fulfill]; + }] + callOptions:options]; + + [call writeWithMessage:request]; + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testRPCAfterClosingOpenConnections { XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = diff --git a/src/objective-c/tests/InteropTestsCallOptions/Info.plist b/src/objective-c/tests/InteropTestsCallOptions/Info.plist new file mode 100644 index 0000000000..6c40a6cd0c --- /dev/null +++ b/src/objective-c/tests/InteropTestsCallOptions/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m b/src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m new file mode 100644 index 0000000000..db51cb1cfb --- /dev/null +++ b/src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m @@ -0,0 +1,116 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import +#import +#import +#import +#import +#import + +#define NSStringize_helper(x) #x +#define NSStringize(x) @NSStringize_helper(x) +static NSString *kRemoteHost = NSStringize(HOST_PORT_REMOTE); +const int32_t kRemoteInteropServerOverhead = 12; + +static const NSTimeInterval TEST_TIMEOUT = 16000; + +@interface InteropTestsCallOptions : XCTestCase + +@end + +@implementation InteropTestsCallOptions { + RMTTestService *_service; +} + +- (void)setUp { + self.continueAfterFailure = NO; + _service = [RMTTestService serviceWithHost:kRemoteHost]; + _service.options = [[GRPCCallOptions alloc] init]; +} + +- (void)test4MBResponsesAreAccepted { + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + const int32_t kPayloadSize = + 4 * 1024 * 1024 - kRemoteInteropServerOverhead; // 4MB - encoding overhead + request.responseSize = kPayloadSize; + + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertEqual(response.payload.body.length, kPayloadSize); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + +- (void)testResponsesOverMaxSizeFailWithActionableMessage { + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + const int32_t kPayloadSize = + 4 * 1024 * 1024 - kRemoteInteropServerOverhead + 1; // 1B over max size + request.responseSize = kPayloadSize; + + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertEqualObjects( + error.localizedDescription, + @"Received message larger than max (4194305 vs. 4194304)"); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + +- (void)testResponsesOver4MBAreAcceptedIfOptedIn { + __weak XCTestExpectation *expectation = + [self expectationWithDescription:@"HigherResponseSizeLimit"]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB + request.responseSize = kPayloadSize; + + GRPCProtoCall *rpc = [_service + RPCToUnaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertEqual(response.payload.body.length, kPayloadSize); + [expectation fulfill]; + }]; + GRPCCallOptions *options = rpc.options; + options.responseSizeLimit = 6 * 1024 * 1024; + + [rpc start]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m index d49e875bd0..42e327a330 100644 --- a/src/objective-c/tests/InteropTestsLocalCleartext.m +++ b/src/objective-c/tests/InteropTestsLocalCleartext.m @@ -41,6 +41,14 @@ static int32_t kLocalInteropServerOverhead = 10; return kLocalCleartextHost; } ++ (NSString *)pemRootCert { + return nil; +} + ++ (NSString *)hostNameOverride { + return nil; +} + - (int32_t)encodingOverhead { return kLocalInteropServerOverhead; // bytes } @@ -52,4 +60,8 @@ static int32_t kLocalInteropServerOverhead = 10; [GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost]; } ++ (GRPCTransportType)transportType { + return GRPCTransportTypeInsecure; +} + @end diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m index a8c4dc7dfd..eb72dd1d31 100644 --- a/src/objective-c/tests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTestsLocalSSL.m @@ -40,10 +40,26 @@ static int32_t kLocalInteropServerOverhead = 10; return kLocalSSLHost; } ++ (NSString *)pemRootCert { + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSString *certsPath = + [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"]; + NSError *error; + return [NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error]; +} + ++ (NSString *)hostNameOverride { + return @"foo.test.google.fr"; +} + - (int32_t)encodingOverhead { return kLocalInteropServerOverhead; // bytes } ++ (GRPCTransportType)transportType { + return GRPCTransportTypeDefault; +} + - (void)setUp { [super setUp]; diff --git a/src/objective-c/tests/InteropTestsMultipleChannels/Info.plist b/src/objective-c/tests/InteropTestsMultipleChannels/Info.plist new file mode 100644 index 0000000000..6c40a6cd0c --- /dev/null +++ b/src/objective-c/tests/InteropTestsMultipleChannels/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m new file mode 100644 index 0000000000..eb0ba7f34b --- /dev/null +++ b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m @@ -0,0 +1,259 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import +#import +#import +#import +#import + +#define NSStringize_helper(x) #x +#define NSStringize(x) @NSStringize_helper(x) +static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE); +static NSString *const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL); +static NSString *const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL); + +static const NSTimeInterval TEST_TIMEOUT = 8000; + +@interface RMTStreamingOutputCallRequest (Constructors) ++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize + requestedResponseSize:(NSNumber *)responseSize; +@end + +@implementation RMTStreamingOutputCallRequest (Constructors) ++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize + requestedResponseSize:(NSNumber *)responseSize { + RMTStreamingOutputCallRequest *request = [self message]; + RMTResponseParameters *parameters = [RMTResponseParameters message]; + parameters.size = responseSize.intValue; + [request.responseParametersArray addObject:parameters]; + request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue]; + return request; +} +@end + +@interface RMTStreamingOutputCallResponse (Constructors) ++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize; +@end + +@implementation RMTStreamingOutputCallResponse (Constructors) ++ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize { + RMTStreamingOutputCallResponse *response = [self message]; + response.payload.type = RMTPayloadType_Compressable; + response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue]; + return response; +} +@end + +@interface InteropTestsMultipleChannels : XCTestCase + +@end + +dispatch_once_t initCronet; + +@implementation InteropTestsMultipleChannels { + RMTTestService *_remoteService; + RMTTestService *_remoteCronetService; + RMTTestService *_localCleartextService; + RMTTestService *_localSSLService; +} + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + // Default stack with remote host + _remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost]; + + // Cronet stack with remote host + _remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost]; + + dispatch_once(&initCronet, ^{ + [Cronet setHttp2Enabled:YES]; + [Cronet start]; + }); + + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + options.transportType = GRPCTransportTypeCronet; + options.cronetEngine = [Cronet getGlobalEngine]; + _remoteCronetService.options = options; + + // Local stack with no SSL + _localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost]; + options = [[GRPCCallOptions alloc] init]; + options.transportType = GRPCTransportTypeInsecure; + _localCleartextService.options = options; + + // Local stack with SSL + _localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost]; + + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSString *certsPath = + [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"]; + NSError *error = nil; + NSString *certs = + [NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error]; + XCTAssertNil(error); + + options = [[GRPCCallOptions alloc] init]; + options.transportType = GRPCTransportTypeDefault; + options.pemRootCert = certs; + options.hostNameOverride = @"foo.test.google.fr"; + _localSSLService.options = options; +} + +- (void)testEmptyUnaryRPC { + __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"]; + __weak XCTestExpectation *expectCronetRemote = + [self expectationWithDescription:@"Remote RPC finish"]; + __weak XCTestExpectation *expectCleartext = + [self expectationWithDescription:@"Remote RPC finish"]; + __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"]; + + GPBEmpty *request = [GPBEmpty message]; + + void (^handler)(GPBEmpty *response, NSError *error) = ^(GPBEmpty *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + + id expectedResponse = [GPBEmpty message]; + XCTAssertEqualObjects(response, expectedResponse); + }; + + [_remoteService emptyCallWithRequest:request + handler:^(GPBEmpty *response, NSError *error) { + handler(response, error); + [expectRemote fulfill]; + }]; + [_remoteCronetService emptyCallWithRequest:request + handler:^(GPBEmpty *response, NSError *error) { + handler(response, error); + [expectCronetRemote fulfill]; + }]; + [_localCleartextService emptyCallWithRequest:request + handler:^(GPBEmpty *response, NSError *error) { + handler(response, error); + [expectCleartext fulfill]; + }]; + [_localSSLService emptyCallWithRequest:request + handler:^(GPBEmpty *response, NSError *error) { + handler(response, error); + [expectSSL fulfill]; + }]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + +- (void)testFullDuplexRPC { + __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"]; + __weak XCTestExpectation *expectCronetRemote = + [self expectationWithDescription:@"Remote RPC finish"]; + __weak XCTestExpectation *expectCleartext = + [self expectationWithDescription:@"Remote RPC finish"]; + __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"]; + + NSArray *requestSizes = @[ @100, @101, @102, @103 ]; + NSArray *responseSizes = @[ @104, @105, @106, @107 ]; + XCTAssertEqual([requestSizes count], [responseSizes count]); + NSUInteger kRounds = [requestSizes count]; + + NSMutableArray *requests = [NSMutableArray arrayWithCapacity:kRounds]; + NSMutableArray *responses = [NSMutableArray arrayWithCapacity:kRounds]; + for (int i = 0; i < kRounds; i++) { + requests[i] = [RMTStreamingOutputCallRequest messageWithPayloadSize:requestSizes[i] + requestedResponseSize:responseSizes[i]]; + responses[i] = [RMTStreamingOutputCallResponse messageWithPayloadSize:responseSizes[i]]; + } + + __block NSMutableArray *steps = [NSMutableArray arrayWithCapacity:4]; + __block NSMutableArray *requestsBuffers = [NSMutableArray arrayWithCapacity:4]; + for (int i = 0; i < 4; i++) { + steps[i] = [NSNumber numberWithUnsignedInteger:0]; + requestsBuffers[i] = [[GRXBufferedPipe alloc] init]; + [requestsBuffers[i] writeValue:requests[0]]; + } + + BOOL (^handler)(int, BOOL, RMTStreamingOutputCallResponse *, NSError *) = + ^(int index, BOOL done, RMTStreamingOutputCallResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertTrue(done || response, @"Event handler called without an event."); + if (response) { + NSUInteger step = [steps[index] unsignedIntegerValue]; + XCTAssertLessThan(step, kRounds, @"More than %lu responses received.", + (unsigned long)kRounds); + XCTAssertEqualObjects(response, responses[step]); + step++; + steps[index] = [NSNumber numberWithUnsignedInteger:step]; + GRXBufferedPipe *pipe = requestsBuffers[index]; + if (step < kRounds) { + [pipe writeValue:requests[step]]; + } else { + [pipe writesFinishedWithError:nil]; + } + } + if (done) { + NSUInteger step = [steps[index] unsignedIntegerValue]; + XCTAssertEqual(step, kRounds, @"Received %lu responses instead of %lu.", step, kRounds); + return YES; + } + return NO; + }; + + [_remoteService + fullDuplexCallWithRequestsWriter:requestsBuffers[0] + eventHandler:^(BOOL done, + RMTStreamingOutputCallResponse *_Nullable response, + NSError *_Nullable error) { + if (handler(0, done, response, error)) { + [expectRemote fulfill]; + } + }]; + [_remoteCronetService + fullDuplexCallWithRequestsWriter:requestsBuffers[1] + eventHandler:^(BOOL done, + RMTStreamingOutputCallResponse *_Nullable response, + NSError *_Nullable error) { + if (handler(1, done, response, error)) { + [expectCronetRemote fulfill]; + } + }]; + [_localCleartextService + fullDuplexCallWithRequestsWriter:requestsBuffers[2] + eventHandler:^(BOOL done, + RMTStreamingOutputCallResponse *_Nullable response, + NSError *_Nullable error) { + if (handler(2, done, response, error)) { + [expectCleartext fulfill]; + } + }]; + [_localSSLService + fullDuplexCallWithRequestsWriter:requestsBuffers[3] + eventHandler:^(BOOL done, + RMTStreamingOutputCallResponse *_Nullable response, + NSError *_Nullable error) { + if (handler(3, done, response, error)) { + [expectSSL fulfill]; + } + }]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + +@end diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m index e5738aac73..516a1f432a 100644 --- a/src/objective-c/tests/InteropTestsRemote.m +++ b/src/objective-c/tests/InteropTestsRemote.m @@ -41,8 +41,26 @@ static int32_t kRemoteInteropServerOverhead = 12; return kRemoteSSLHost; } ++ (NSString *)pemRootCert { + return nil; +} + ++ (NSString *)hostNameOverride { + return nil; +} + - (int32_t)encodingOverhead { return kRemoteInteropServerOverhead; // bytes } +#ifdef GRPC_COMPILE_WITH_CRONET ++ (GRPCTransportType)transportType { + return GRPCTransportTypeCronet; +} +#else ++ (GRPCTransportType)transportType { + return GRPCTransportTypeDefault; +} +#endif + @end diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index 5d2f1340da..e87aba235a 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -14,6 +14,8 @@ GRPC_LOCAL_SRC = '../../..' InteropTestsLocalSSL InteropTestsLocalCleartext InteropTestsRemoteWithCronet + InteropTestsMultipleChannels + InteropTestsCallOptions UnitTests ).each do |target_name| target target_name do @@ -30,7 +32,7 @@ GRPC_LOCAL_SRC = '../../..' pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true - if target_name == 'InteropTestsRemoteWithCronet' + if target_name == 'InteropTestsRemoteWithCronet' or target_name == 'InteropTestsMultipleChannels' pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" end @@ -72,6 +74,12 @@ end end end +target 'ChannelTests' do + pod 'gRPC', :path => GRPC_LOCAL_SRC + pod 'gRPC-Core', :path => GRPC_LOCAL_SRC + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true +end + # gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's # pre_install hook lets us do that. The block passed to it runs after the podspecs are downloaded # and before they are installed in the user project. diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index f0d8123263..104fd0a4ea 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -11,14 +11,23 @@ 09B76D9585ACE7403804D9DC /* libPods-InteropTestsRemoteWithCronet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */; }; 0F9232F984C08643FD40C34F /* libPods-InteropTestsRemote.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */; }; 16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */; }; + 1A0FB7F8C95A2F82538BC950 /* libPods-ChannelTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 48F1841C9A920626995DC28C /* libPods-ChannelTests.a */; }; 20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; }; 333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; }; 5E0282E9215AA697007AC99D /* UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* UnitTests.m */; }; 5E0282EB215AA697007AC99D /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; + 5E7D71AD210954A8001EA6BA /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; + 5E7D71B5210B9EC9001EA6BA /* InteropTestsCallOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */; }; + 5E7D71B7210B9EC9001EA6BA /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; 5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */; }; 5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; 5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.m */; }; 5EAD6D291E27047400002378 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; + 5EB2A2E72107DED300EB4B69 /* ChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EB2A2E62107DED300EB4B69 /* ChannelTests.m */; }; + 5EB2A2E92107DED300EB4B69 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; + 5EB2A2F82109284500EB4B69 /* InteropTestsMultipleChannels.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EB2A2F72109284500EB4B69 /* InteropTestsMultipleChannels.m */; }; + 5EB2A2FA2109284500EB4B69 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; + 5EB5C3AA21656CEA00ADC300 /* ChannelPoolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EB5C3A921656CEA00ADC300 /* ChannelPoolTest.m */; }; 5EC5E42B2081782C000EF4AD /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; }; 5EC5E42C20817832000EF4AD /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; }; 5EC5E43B208185A7000EF4AD /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; }; @@ -53,6 +62,8 @@ 63DC84501BE153AA000708E8 /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; }; 63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; }; 63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; + 6C1A3F81CCF7C998B4813EFD /* libPods-InteropTestsCallOptions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF3FC2CFFE7B0961823BC740 /* libPods-InteropTestsCallOptions.a */; }; + 886717A79EFF774F356798E6 /* libPods-InteropTestsMultipleChannels.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 355D0E30AD224763BC9519F4 /* libPods-InteropTestsMultipleChannels.a */; }; 91D4B3C85B6D8562F409CB48 /* libPods-InteropTestsLocalSSLCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */; }; BC111C80CBF7068B62869352 /* libPods-InteropTestsRemoteCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */; }; C3D6F4270A2FFF634D8849ED /* libPods-InteropTestsLocalCleartextCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */; }; @@ -68,6 +79,13 @@ remoteGlobalIDString = 635697C61B14FC11007A7283; remoteInfo = Tests; }; + 5E7D71B8210B9EC9001EA6BA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; 5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 635697BF1B14FC11007A7283 /* Project object */; @@ -82,6 +100,20 @@ remoteGlobalIDString = 635697C61B14FC11007A7283; remoteInfo = Tests; }; + 5EB2A2EA2107DED300EB4B69 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; + 5EB2A2FB2109284500EB4B69 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 635697BF1B14FC11007A7283 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 635697C61B14FC11007A7283; + remoteInfo = Tests; + }; 5EE84BF71D4717E40050C6CC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 635697BF1B14FC11007A7283 /* Project object */; @@ -144,20 +176,26 @@ 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartextCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.debug.xcconfig"; sourceTree = ""; }; + 1295CCBD1082B4A7CFCED95F /* Pods-InteropTestsMultipleChannels.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsMultipleChannels.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels.cronet.xcconfig"; sourceTree = ""; }; 14B09A58FEE53A7A6B838920 /* Pods-InteropTestsLocalSSL.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.cronet.xcconfig"; sourceTree = ""; }; 1588C85DEAF7FC0ACDEA4C02 /* Pods-InteropTestsLocalCleartext.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.test.xcconfig"; sourceTree = ""; }; 17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; sourceTree = ""; }; 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-UnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2650FEF00956E7924772F9D9 /* Pods-InteropTestsMultipleChannels.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsMultipleChannels.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels.release.xcconfig"; sourceTree = ""; }; 2B89F3037963E6EDDD48D8C3 /* Pods-InteropTestsRemoteWithCronet.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.test.xcconfig"; sourceTree = ""; }; 303F4A17EB1650FC44603D17 /* Pods-InteropTestsRemoteCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.release.xcconfig"; sourceTree = ""; }; 32748C4078AEB05F8F954361 /* Pods-InteropTestsRemoteCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.debug.xcconfig"; sourceTree = ""; }; + 355D0E30AD224763BC9519F4 /* libPods-InteropTestsMultipleChannels.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsMultipleChannels.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 386712AEACF7C2190C4B8B3F /* Pods-CronetUnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.cronet.xcconfig"; sourceTree = ""; }; + 3A98DF08852F60AF1D96481D /* Pods-InteropTestsCallOptions.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsCallOptions.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions.debug.xcconfig"; sourceTree = ""; }; 3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.release.xcconfig"; sourceTree = ""; }; + 3CADF86203B9D03EA96C359D /* Pods-InteropTestsMultipleChannels.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsMultipleChannels.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels.debug.xcconfig"; sourceTree = ""; }; 3EB55EF291706E3DDE23C3B7 /* Pods-InteropTestsLocalSSLCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.debug.xcconfig"; sourceTree = ""; }; 3F27B2E744482771EB93C394 /* Pods-InteropTestsRemoteWithCronet.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.cronet.xcconfig"; sourceTree = ""; }; 41AA59529240A6BBBD3DB904 /* Pods-InteropTestsLocalSSLCFStream.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.test.xcconfig"; sourceTree = ""; }; + 48F1841C9A920626995DC28C /* libPods-ChannelTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ChannelTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 4A1A42B2E941CCD453489E5B /* Pods-InteropTestsRemoteCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.cronet.xcconfig"; sourceTree = ""; }; 4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.release.xcconfig"; sourceTree = ""; }; 4ADEA1C8BBE10D90940AC68E /* Pods-InteropTestsRemote.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.cronet.xcconfig"; sourceTree = ""; }; @@ -169,6 +207,9 @@ 5E0282E6215AA697007AC99D /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5E0282E8215AA697007AC99D /* UnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnitTests.m; sourceTree = ""; }; 5E0282EA215AA697007AC99D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsCallOptions.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsCallOptions.m; sourceTree = ""; }; + 5E7D71B6210B9EC9001EA6BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreCronetEnd2EndTests.mm; sourceTree = ""; }; 5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; sourceTree = ""; }; @@ -176,6 +217,13 @@ 5EAD6D261E27047400002378 /* CronetUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CronetUnitTests.m; sourceTree = ""; }; 5EAD6D281E27047400002378 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5EAFE8271F8EFB87007F2189 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = ""; }; + 5EB2A2E42107DED300EB4B69 /* ChannelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ChannelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5EB2A2E62107DED300EB4B69 /* ChannelTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChannelTests.m; sourceTree = ""; }; + 5EB2A2E82107DED300EB4B69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsMultipleChannels.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5EB2A2F72109284500EB4B69 /* InteropTestsMultipleChannels.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsMultipleChannels.m; sourceTree = ""; }; + 5EB2A2F92109284500EB4B69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5EB5C3A921656CEA00ADC300 /* ChannelPoolTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChannelPoolTest.m; sourceTree = ""; }; 5EC5E421208177CC000EF4AD /* InteropTestsRemoteCFStream.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemoteCFStream.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5EC5E4312081856B000EF4AD /* InteropTestsLocalCleartextCFStream.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalCleartextCFStream.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5EC5E442208185CE000EF4AD /* InteropTestsLocalSSLCFStream.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsLocalSSLCFStream.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -200,25 +248,32 @@ 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = ""; }; 64F68A9A6A63CC930DD30A6E /* Pods-CronetUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.debug.xcconfig"; sourceTree = ""; }; 6793C9D019CB268C5BB491A2 /* Pods-CoreCronetEnd2EndTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.test.xcconfig"; sourceTree = ""; }; + 73D2DF07027835BA0FB0B1C0 /* Pods-InteropTestsCallOptions.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsCallOptions.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions.cronet.xcconfig"; sourceTree = ""; }; 781089FAE980F51F88A3BE0B /* Pods-RxLibraryUnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.test.xcconfig"; sourceTree = ""; }; 79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.cronet.xcconfig"; sourceTree = ""; }; 7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.release.xcconfig"; sourceTree = ""; }; 7BA53C6D224288D5870FE6F3 /* Pods-InteropTestsLocalCleartextCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; sourceTree = ""; }; 8B498B05C6DA0818B2FA91D4 /* Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; sourceTree = ""; }; + 90E63AD3C4A1E3E6BC745096 /* Pods-ChannelTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.cronet.xcconfig"; sourceTree = ""; }; 943138072A9605B5B8DC1FC0 /* Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; sourceTree = ""; }; 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.test.xcconfig"; sourceTree = ""; }; 9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteWithCronet.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + A25967A0D40ED14B3287AD81 /* Pods-InteropTestsCallOptions.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsCallOptions.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions.test.xcconfig"; sourceTree = ""; }; A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.debug.xcconfig"; sourceTree = ""; }; A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RxLibraryUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; A6F832FCEFA6F6881E620F12 /* Pods-InteropTestsRemote.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.test.xcconfig"; sourceTree = ""; }; AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.cronet.xcconfig"; sourceTree = ""; }; AC414EF7A6BF76ED02B6E480 /* Pods-InteropTestsRemoteWithCronet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.release.xcconfig"; sourceTree = ""; }; + AF3FC2CFFE7B0961823BC740 /* libPods-InteropTestsCallOptions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsCallOptions.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B226619DC4E709E0FFFF94B8 /* Pods-CronetUnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.test.xcconfig"; sourceTree = ""; }; B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.debug.xcconfig"; sourceTree = ""; }; + BED74BC8ABF9917C66175879 /* Pods-ChannelTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.test.xcconfig"; sourceTree = ""; }; C17F57E5BCB989AB1C2F1F25 /* Pods-InteropTestsRemoteCFStream.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.test.xcconfig"; sourceTree = ""; }; C6134277D2EB8B380862A03F /* libPods-CronetUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CronetUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + C9172F9020E8C97A470D7250 /* Pods-InteropTestsCallOptions.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsCallOptions.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions.release.xcconfig"; sourceTree = ""; }; CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AllTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; D13BEC8181B8E678A1B52F54 /* Pods-InteropTestsLocalSSL.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.test.xcconfig"; sourceTree = ""; }; + D52B92A7108602F170DA8091 /* Pods-ChannelTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.release.xcconfig"; sourceTree = ""; }; DB1F4391AF69D20D38D74B67 /* Pods-AllTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.test.xcconfig"; sourceTree = ""; }; DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemote.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSL.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -228,9 +283,11 @@ E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.release.xcconfig"; sourceTree = ""; }; E4FD4606D4AB8D5A314D72F0 /* Pods-InteropTestsLocalCleartextCFStream.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.test.xcconfig"; sourceTree = ""; }; E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.cronet.xcconfig"; sourceTree = ""; }; + EA8B122ACDE73E3AAA0E4A19 /* Pods-InteropTestsMultipleChannels.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsMultipleChannels.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels.test.xcconfig"; sourceTree = ""; }; EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.release.xcconfig"; sourceTree = ""; }; F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSLCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + F9E48EF5ACB1F38825171C5F /* Pods-ChannelTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.debug.xcconfig"; sourceTree = ""; }; FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CoreCronetEnd2EndTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartext.a"; sourceTree = BUILT_PRODUCTS_DIR; }; FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; @@ -246,6 +303,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E7D71AF210B9EC8001EA6BA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E7D71B7210B9EC9001EA6BA /* libTests.a in Frameworks */, + 6C1A3F81CCF7C998B4813EFD /* libPods-InteropTestsCallOptions.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E8A5DA11D3840B4000F8BC4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -264,6 +330,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5EB2A2E12107DED300EB4B69 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5EB2A2E92107DED300EB4B69 /* libTests.a in Frameworks */, + 1A0FB7F8C95A2F82538BC950 /* libPods-ChannelTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5EB2A2F22109284500EB4B69 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5EB2A2FA2109284500EB4B69 /* libTests.a in Frameworks */, + 886717A79EFF774F356798E6 /* libPods-InteropTestsMultipleChannels.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5EC5E41E208177CC000EF4AD /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -368,6 +452,9 @@ F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */, 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */, F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */, + 48F1841C9A920626995DC28C /* libPods-ChannelTests.a */, + 355D0E30AD224763BC9519F4 /* libPods-InteropTestsMultipleChannels.a */, + AF3FC2CFFE7B0961823BC740 /* libPods-InteropTestsCallOptions.a */, 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */, ); name = Frameworks; @@ -422,6 +509,18 @@ 41AA59529240A6BBBD3DB904 /* Pods-InteropTestsLocalSSLCFStream.test.xcconfig */, 55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */, 5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */, + F9E48EF5ACB1F38825171C5F /* Pods-ChannelTests.debug.xcconfig */, + BED74BC8ABF9917C66175879 /* Pods-ChannelTests.test.xcconfig */, + 90E63AD3C4A1E3E6BC745096 /* Pods-ChannelTests.cronet.xcconfig */, + D52B92A7108602F170DA8091 /* Pods-ChannelTests.release.xcconfig */, + 3CADF86203B9D03EA96C359D /* Pods-InteropTestsMultipleChannels.debug.xcconfig */, + EA8B122ACDE73E3AAA0E4A19 /* Pods-InteropTestsMultipleChannels.test.xcconfig */, + 1295CCBD1082B4A7CFCED95F /* Pods-InteropTestsMultipleChannels.cronet.xcconfig */, + 2650FEF00956E7924772F9D9 /* Pods-InteropTestsMultipleChannels.release.xcconfig */, + 3A98DF08852F60AF1D96481D /* Pods-InteropTestsCallOptions.debug.xcconfig */, + A25967A0D40ED14B3287AD81 /* Pods-InteropTestsCallOptions.test.xcconfig */, + 73D2DF07027835BA0FB0B1C0 /* Pods-InteropTestsCallOptions.cronet.xcconfig */, + C9172F9020E8C97A470D7250 /* Pods-InteropTestsCallOptions.release.xcconfig */, A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */, 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */, E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */, @@ -439,6 +538,15 @@ path = UnitTests; sourceTree = ""; }; + 5E7D71B3210B9EC9001EA6BA /* InteropTestsCallOptions */ = { + isa = PBXGroup; + children = ( + 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */, + 5E7D71B6210B9EC9001EA6BA /* Info.plist */, + ); + path = InteropTestsCallOptions; + sourceTree = ""; + }; 5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = { isa = PBXGroup; children = ( @@ -456,6 +564,25 @@ path = CronetUnitTests; sourceTree = ""; }; + 5EB2A2E52107DED300EB4B69 /* ChannelTests */ = { + isa = PBXGroup; + children = ( + 5EB5C3A921656CEA00ADC300 /* ChannelPoolTest.m */, + 5EB2A2E62107DED300EB4B69 /* ChannelTests.m */, + 5EB2A2E82107DED300EB4B69 /* Info.plist */, + ); + path = ChannelTests; + sourceTree = ""; + }; + 5EB2A2F62109284500EB4B69 /* InteropTestsMultipleChannels */ = { + isa = PBXGroup; + children = ( + 5EB2A2F72109284500EB4B69 /* InteropTestsMultipleChannels.m */, + 5EB2A2F92109284500EB4B69 /* Info.plist */, + ); + path = InteropTestsMultipleChannels; + sourceTree = ""; + }; 5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */ = { isa = PBXGroup; children = ( @@ -473,6 +600,9 @@ 5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */, 5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */, 5EAD6D251E27047400002378 /* CronetUnitTests */, + 5EB2A2E52107DED300EB4B69 /* ChannelTests */, + 5EB2A2F62109284500EB4B69 /* InteropTestsMultipleChannels */, + 5E7D71B3210B9EC9001EA6BA /* InteropTestsCallOptions */, 5E0282E7215AA697007AC99D /* UnitTests */, 635697C81B14FC11007A7283 /* Products */, 51E4650F34F854F41FF053B3 /* Pods */, @@ -495,6 +625,9 @@ 5EC5E421208177CC000EF4AD /* InteropTestsRemoteCFStream.xctest */, 5EC5E4312081856B000EF4AD /* InteropTestsLocalCleartextCFStream.xctest */, 5EC5E442208185CE000EF4AD /* InteropTestsLocalSSLCFStream.xctest */, + 5EB2A2E42107DED300EB4B69 /* ChannelTests.xctest */, + 5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */, + 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */, 5E0282E6215AA697007AC99D /* UnitTests.xctest */, ); name = Products; @@ -548,6 +681,26 @@ productReference = 5E0282E6215AA697007AC99D /* UnitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E7D71BA210B9EC9001EA6BA /* Build configuration list for PBXNativeTarget "InteropTestsCallOptions" */; + buildPhases = ( + 2865C6386D677998F861E183 /* [CP] Check Pods Manifest.lock */, + 5E7D71AE210B9EC8001EA6BA /* Sources */, + 5E7D71AF210B9EC8001EA6BA /* Frameworks */, + 5E7D71B0210B9EC8001EA6BA /* Resources */, + 6BA6D00B1816306453BF82D4 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5E7D71B9210B9EC9001EA6BA /* PBXTargetDependency */, + ); + name = InteropTestsCallOptions; + productName = InteropTestsCallOptions; + productReference = 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = { isa = PBXNativeTarget; buildConfigurationList = 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */; @@ -588,6 +741,47 @@ productReference = 5EAD6D241E27047400002378 /* CronetUnitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 5EB2A2E32107DED300EB4B69 /* ChannelTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5EB2A2F02107DED300EB4B69 /* Build configuration list for PBXNativeTarget "ChannelTests" */; + buildPhases = ( + 021B3B1F545989843EBC9A4B /* [CP] Check Pods Manifest.lock */, + 5EB2A2E02107DED300EB4B69 /* Sources */, + 5EB2A2E12107DED300EB4B69 /* Frameworks */, + 5EB2A2E22107DED300EB4B69 /* Resources */, + 1EAF0CBDBFAB18D4DA64535D /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5EB2A2EB2107DED300EB4B69 /* PBXTargetDependency */, + ); + name = ChannelTests; + productName = ChannelTests; + productReference = 5EB2A2E42107DED300EB4B69 /* ChannelTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 5EB2A2F42109284500EB4B69 /* InteropTestsMultipleChannels */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5EB2A3012109284500EB4B69 /* Build configuration list for PBXNativeTarget "InteropTestsMultipleChannels" */; + buildPhases = ( + 8C1ED025E07C4D457C355336 /* [CP] Check Pods Manifest.lock */, + 5EB2A2F12109284500EB4B69 /* Sources */, + 5EB2A2F22109284500EB4B69 /* Frameworks */, + 5EB2A2F32109284500EB4B69 /* Resources */, + 8D685CB612835DB3F7A6F14A /* [CP] Embed Pods Frameworks */, + 0617B5294978A95BEBBFF733 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5EB2A2FC2109284500EB4B69 /* PBXTargetDependency */, + ); + name = InteropTestsMultipleChannels; + productName = InteropTestsMultipleChannels; + productReference = 5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 5EC5E420208177CC000EF4AD /* InteropTestsRemoteCFStream */ = { isa = PBXNativeTarget; buildConfigurationList = 5EC5E42A208177CD000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsRemoteCFStream" */; @@ -796,12 +990,24 @@ CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; }; + 5E7D71B1210B9EC8001EA6BA = { + CreatedOnToolsVersion = 9.3; + ProvisioningStyle = Automatic; + }; 5E8A5DA31D3840B4000F8BC4 = { CreatedOnToolsVersion = 7.3.1; }; 5EAD6D231E27047400002378 = { CreatedOnToolsVersion = 7.3.1; }; + 5EB2A2E32107DED300EB4B69 = { + CreatedOnToolsVersion = 9.3; + ProvisioningStyle = Automatic; + }; + 5EB2A2F42109284500EB4B69 = { + CreatedOnToolsVersion = 9.3; + ProvisioningStyle = Automatic; + }; 5EC5E420208177CC000EF4AD = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; @@ -861,6 +1067,9 @@ 5EC5E420208177CC000EF4AD /* InteropTestsRemoteCFStream */, 5EC5E4302081856B000EF4AD /* InteropTestsLocalCleartextCFStream */, 5EC5E441208185CE000EF4AD /* InteropTestsLocalSSLCFStream */, + 5EB2A2E32107DED300EB4B69 /* ChannelTests */, + 5EB2A2F42109284500EB4B69 /* InteropTestsMultipleChannels */, + 5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */, 5E0282E5215AA697007AC99D /* UnitTests */, ); }; @@ -874,6 +1083,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E7D71B0210B9EC8001EA6BA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E8A5DA21D3840B4000F8BC4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -888,6 +1104,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5EB2A2E22107DED300EB4B69 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5EB2A2F32109284500EB4B69 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E7D71AD210954A8001EA6BA /* TestCertificates.bundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5EC5E41F208177CC000EF4AD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -957,6 +1188,60 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 021B3B1F545989843EBC9A4B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ChannelTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 0617B5294978A95BEBBFF733 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 1EAF0CBDBFAB18D4DA64535D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 252A376345E38FD452A89C3D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -975,6 +1260,24 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 2865C6386D677998F861E183 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-InteropTestsCallOptions-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 31F8D1C407195CBF0C02929B /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1083,6 +1386,24 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 6BA6D00B1816306453BF82D4 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsCallOptions/Pods-InteropTestsCallOptions-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 7418AC7B3844B29E48D24FC7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1137,6 +1458,42 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 8C1ED025E07C4D457C355336 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-InteropTestsMultipleChannels-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8D685CB612835DB3F7A6F14A /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-frameworks.sh", + "${PODS_ROOT}/CronetFramework/Cronet.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 914ADDD7106BA9BB8A7E569F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1418,6 +1775,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E7D71AE210B9EC8001EA6BA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E7D71B5210B9EC9001EA6BA /* InteropTestsCallOptions.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E8A5DA01D3840B4000F8BC4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1434,6 +1799,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5EB2A2E02107DED300EB4B69 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5EB2A2E72107DED300EB4B69 /* ChannelTests.m in Sources */, + 5EB5C3AA21656CEA00ADC300 /* ChannelPoolTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5EB2A2F12109284500EB4B69 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5EB2A2F82109284500EB4B69 /* InteropTestsMultipleChannels.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5EC5E41D208177CC000EF4AD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1536,6 +1918,11 @@ target = 635697C61B14FC11007A7283 /* Tests */; targetProxy = 5E0282EC215AA697007AC99D /* PBXContainerItemProxy */; }; + 5E7D71B9210B9EC9001EA6BA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 5E7D71B8210B9EC9001EA6BA /* PBXContainerItemProxy */; + }; 5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 635697C61B14FC11007A7283 /* Tests */; @@ -1546,6 +1933,16 @@ target = 635697C61B14FC11007A7283 /* Tests */; targetProxy = 5EAD6D2A1E27047400002378 /* PBXContainerItemProxy */; }; + 5EB2A2EB2107DED300EB4B69 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 5EB2A2EA2107DED300EB4B69 /* PBXContainerItemProxy */; + }; + 5EB2A2FC2109284500EB4B69 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 635697C61B14FC11007A7283 /* Tests */; + targetProxy = 5EB2A2FB2109284500EB4B69 /* PBXContainerItemProxy */; + }; 5EE84BF81D4717E40050C6CC /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 635697C61B14FC11007A7283 /* Tests */; @@ -1909,16 +2306,146 @@ }; name = Test; }; - 5E8A5DAC1D3840B4000F8BC4 /* Debug */ = { + 5E7D71BB210B9EC9001EA6BA /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */; + baseConfigurationReference = 3A98DF08852F60AF1D96481D /* Pods-InteropTestsCallOptions.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_TESTABILITY = YES; - INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.3; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsCallOptions/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5E7D71BC210B9EC9001EA6BA /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A25967A0D40ED14B3287AD81 /* Pods-InteropTestsCallOptions.test.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsCallOptions/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Test; + }; + 5E7D71BD210B9EC9001EA6BA /* Cronet */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 73D2DF07027835BA0FB0B1C0 /* Pods-InteropTestsCallOptions.cronet.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsCallOptions/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Cronet; + }; + 5E7D71BE210B9EC9001EA6BA /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C9172F9020E8C97A470D7250 /* Pods-InteropTestsCallOptions.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsCallOptions/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsCallOptions; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 5E8A5DAC1D3840B4000F8BC4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -2011,6 +2538,266 @@ }; name = Release; }; + 5EB2A2EC2107DED300EB4B69 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F9E48EF5ACB1F38825171C5F /* Pods-ChannelTests.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = ChannelTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5EB2A2ED2107DED300EB4B69 /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BED74BC8ABF9917C66175879 /* Pods-ChannelTests.test.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = ChannelTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Test; + }; + 5EB2A2EE2107DED300EB4B69 /* Cronet */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 90E63AD3C4A1E3E6BC745096 /* Pods-ChannelTests.cronet.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = ChannelTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Cronet; + }; + 5EB2A2EF2107DED300EB4B69 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D52B92A7108602F170DA8091 /* Pods-ChannelTests.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = ChannelTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ChannelTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 5EB2A2FD2109284500EB4B69 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3CADF86203B9D03EA96C359D /* Pods-InteropTestsMultipleChannels.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5EB2A2FE2109284500EB4B69 /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EA8B122ACDE73E3AAA0E4A19 /* Pods-InteropTestsMultipleChannels.test.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Test; + }; + 5EB2A2FF2109284500EB4B69 /* Cronet */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1295CCBD1082B4A7CFCED95F /* Pods-InteropTestsMultipleChannels.cronet.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Cronet; + }; + 5EB2A3002109284500EB4B69 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2650FEF00956E7924772F9D9 /* Pods-InteropTestsMultipleChannels.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = InteropTestsMultipleChannels/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsMultipleChannels; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 5EC3C7A01D4FC18C000330E2 /* Cronet */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2039,6 +2826,8 @@ "DEBUG=1", "$(inherited)", "HOST_PORT_REMOTE=$(HOST_PORT_REMOTE)", + "HOST_PORT_LOCALSSL=$(HOST_PORT_LOCALSSL)", + "HOST_PORT_LOCAL=$(HOST_PORT_LOCAL)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_TREAT_WARNINGS_AS_ERRORS = YES; @@ -2859,6 +3648,17 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5E7D71BA210B9EC9001EA6BA /* Build configuration list for PBXNativeTarget "InteropTestsCallOptions" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E7D71BB210B9EC9001EA6BA /* Debug */, + 5E7D71BC210B9EC9001EA6BA /* Test */, + 5E7D71BD210B9EC9001EA6BA /* Cronet */, + 5E7D71BE210B9EC9001EA6BA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -2881,6 +3681,28 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5EB2A2F02107DED300EB4B69 /* Build configuration list for PBXNativeTarget "ChannelTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5EB2A2EC2107DED300EB4B69 /* Debug */, + 5EB2A2ED2107DED300EB4B69 /* Test */, + 5EB2A2EE2107DED300EB4B69 /* Cronet */, + 5EB2A2EF2107DED300EB4B69 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5EB2A3012109284500EB4B69 /* Build configuration list for PBXNativeTarget "InteropTestsMultipleChannels" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5EB2A2FD2109284500EB4B69 /* Debug */, + 5EB2A2FE2109284500EB4B69 /* Test */, + 5EB2A2FF2109284500EB4B69 /* Cronet */, + 5EB2A3002109284500EB4B69 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 5EC5E42A208177CD000EF4AD /* Build configuration list for PBXNativeTarget "InteropTestsRemoteCFStream" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme new file mode 100644 index 0000000000..16ae481123 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme new file mode 100644 index 0000000000..dd83282190 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme index 510115fc75..11b41c9214 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme @@ -26,7 +26,6 @@ buildConfiguration = "Test" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - @@ -58,7 +51,6 @@ buildConfiguration = "Test" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme new file mode 100644 index 0000000000..1b4c1f5e51 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme index 48837e57f9..412bf6a014 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme @@ -26,7 +26,6 @@ buildConfiguration = "Test" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> Date: Mon, 8 Oct 2018 15:49:17 -0700 Subject: Proto-related changes --- src/compiler/objective_c_generator.cc | 103 ++++++++++++++++++++- src/compiler/objective_c_generator.h | 7 +- src/compiler/objective_c_plugin.cc | 21 ++++- src/objective-c/ProtoRPC/ProtoRPC.h | 49 ++++++++++ src/objective-c/ProtoRPC/ProtoRPC.m | 157 ++++++++++++++++++++++++++++++++ src/objective-c/ProtoRPC/ProtoService.h | 28 +++++- src/objective-c/ProtoRPC/ProtoService.m | 47 +++++++++- 7 files changed, 399 insertions(+), 13 deletions(-) diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc index 39f68cb956..eb67e9bb88 100644 --- a/src/compiler/objective_c_generator.cc +++ b/src/compiler/objective_c_generator.cc @@ -113,6 +113,29 @@ void PrintAdvancedSignature(Printer* printer, const MethodDescriptor* method, PrintMethodSignature(printer, method, vars); } +void PrintV2Signature(Printer* printer, const MethodDescriptor* method, + map< ::grpc::string, ::grpc::string> vars) { + if (method->client_streaming()) { + vars["return_type"] = "GRPCStreamingProtoCall *"; + } else { + vars["return_type"] = "GRPCUnaryProtoCall *"; + } + vars["method_name"] = + grpc_generator::LowercaseFirstLetter(vars["method_name"]); + + PrintAllComments(method, printer); + + printer->Print(vars, "- ($return_type$)$method_name$With"); + if (method->client_streaming()) { + printer->Print("ResponseHandler:(id)handler"); + } else { + printer->Print(vars, + "Message:($request_class$ *)message " + "responseHandler:(id)handler"); + } + printer->Print(" callOptions:(GRPCCallOptions *_Nullable)callOptions"); +} + inline map< ::grpc::string, ::grpc::string> GetMethodVars( const MethodDescriptor* method) { map< ::grpc::string, ::grpc::string> res; @@ -135,6 +158,16 @@ void PrintMethodDeclarations(Printer* printer, const MethodDescriptor* method) { printer->Print(";\n\n\n"); } +void PrintV2MethodDeclarations(Printer* printer, + const MethodDescriptor* method) { + map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method); + + PrintProtoRpcDeclarationAsPragma(printer, method, vars); + + PrintV2Signature(printer, method, vars); + printer->Print(";\n\n"); +} + void PrintSimpleImplementation(Printer* printer, const MethodDescriptor* method, map< ::grpc::string, ::grpc::string> vars) { printer->Print("{\n"); @@ -177,6 +210,25 @@ void PrintAdvancedImplementation(Printer* printer, printer->Print("}\n"); } +void PrintV2Implementation(Printer* printer, const MethodDescriptor* method, + map< ::grpc::string, ::grpc::string> vars) { + printer->Print(" {\n"); + if (method->client_streaming()) { + printer->Print(vars, " return [self RPCToMethod:@\"$method_name$\"\n"); + printer->Print(" responseHandler:handler\n"); + printer->Print(" callOptions:callOptions\n"); + printer->Print( + vars, " responseClass:[$response_class$ class]];\n}\n\n"); + } else { + printer->Print(vars, " return [self RPCToMethod:@\"$method_name$\"\n"); + printer->Print(" message:message\n"); + printer->Print(" responseHandler:handler\n"); + printer->Print(" callOptions:callOptions\n"); + printer->Print( + vars, " responseClass:[$response_class$ class]];\n}\n\n"); + } +} + void PrintMethodImplementations(Printer* printer, const MethodDescriptor* method) { map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method); @@ -184,12 +236,16 @@ void PrintMethodImplementations(Printer* printer, PrintProtoRpcDeclarationAsPragma(printer, method, vars); // TODO(jcanizales): Print documentation from the method. + printer->Print("// Deprecated methods.\n"); PrintSimpleSignature(printer, method, vars); PrintSimpleImplementation(printer, method, vars); printer->Print("// Returns a not-yet-started RPC object.\n"); PrintAdvancedSignature(printer, method, vars); PrintAdvancedImplementation(printer, method, vars); + + PrintV2Signature(printer, method, vars); + PrintV2Implementation(printer, method, vars); } } // namespace @@ -231,6 +287,25 @@ void PrintMethodImplementations(Printer* printer, return output; } +::grpc::string GetV2Protocol(const ServiceDescriptor* service) { + ::grpc::string output; + + // Scope the output stream so it closes and finalizes output to the string. + grpc::protobuf::io::StringOutputStream output_stream(&output); + Printer printer(&output_stream, '$'); + + map< ::grpc::string, ::grpc::string> vars = { + {"service_class", ServiceClassName(service) + "2"}}; + + printer.Print(vars, "@protocol $service_class$ \n\n"); + for (int i = 0; i < service->method_count(); i++) { + PrintV2MethodDeclarations(&printer, service->method(i)); + } + printer.Print("@end\n\n"); + + return output; +} + ::grpc::string GetInterface(const ServiceDescriptor* service) { ::grpc::string output; @@ -248,10 +323,16 @@ void PrintMethodImplementations(Printer* printer, " */\n"); printer.Print(vars, "@interface $service_class$ :" - " GRPCProtoService<$service_class$>\n"); + " GRPCProtoService<$service_class$, $service_class$2>\n"); printer.Print( - "- (instancetype)initWithHost:(NSString *)host" + "- (instancetype)initWithHost:(NSString *)host " + "callOptions:(GRPCCallOptions " + "*_Nullable)callOptions" " NS_DESIGNATED_INITIALIZER;\n"); + printer.Print("- (instancetype)initWithHost:(NSString *)host;\n"); + printer.Print( + "+ (instancetype)serviceWithHost:(NSString *)host " + "callOptions:(GRPCCallOptions *_Nullable)callOptions;\n"); printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n"); printer.Print("@end\n"); @@ -273,11 +354,19 @@ void PrintMethodImplementations(Printer* printer, printer.Print(vars, "@implementation $service_class$\n\n" "// Designated initializer\n" - "- (instancetype)initWithHost:(NSString *)host {\n" + "- (instancetype)initWithHost:(NSString *)host " + "callOptions:(GRPCCallOptions *_Nullable)callOptions{\n" " self = [super initWithHost:host\n" " packageName:@\"$package$\"\n" - " serviceName:@\"$service_name$\"];\n" + " serviceName:@\"$service_name$\"\n" + " callOptions:callOptions];\n" " return self;\n" + "}\n\n" + "- (instancetype)initWithHost:(NSString *)host {\n" + " return [self initWithHost:host\n" + " packageName:@\"$package$\"\n" + " serviceName:@\"$service_name$\"\n" + " callOptions:nil];\n" "}\n\n"); printer.Print( @@ -292,7 +381,11 @@ void PrintMethodImplementations(Printer* printer, printer.Print( "#pragma mark - Class Methods\n\n" "+ (instancetype)serviceWithHost:(NSString *)host {\n" - " return [[self alloc] initWithHost:host];\n" + " return [self serviceWithHost:host callOptions:nil];\n" + "}\n\n" + "+ (instancetype)serviceWithHost:(NSString *)host " + "callOptions:(GRPCCallOptions *_Nullable)callOptions {\n" + " return [[self alloc] initWithHost:host callOptions:callOptions];\n" "}\n\n"); printer.Print("#pragma mark - Method Implementations\n\n"); diff --git a/src/compiler/objective_c_generator.h b/src/compiler/objective_c_generator.h index eb1c7ff005..c171e5bf77 100644 --- a/src/compiler/objective_c_generator.h +++ b/src/compiler/objective_c_generator.h @@ -32,9 +32,14 @@ using ::grpc::string; string GetAllMessageClasses(const FileDescriptor* file); // Returns the content to be included defining the @protocol segment at the -// insertion point of the generated implementation file. +// insertion point of the generated implementation file. This interface is +// legacy and for backwards compatibility. string GetProtocol(const ServiceDescriptor* service); +// Returns the content to be included defining the @protocol segment at the +// insertion point of the generated implementation file. +string GetV2Protocol(const ServiceDescriptor* service); + // Returns the content to be included defining the @interface segment at the // insertion point of the generated implementation file. string GetInterface(const ServiceDescriptor* service); diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc index f0fe3688cc..d0ef9ed0d6 100644 --- a/src/compiler/objective_c_plugin.cc +++ b/src/compiler/objective_c_plugin.cc @@ -93,7 +93,13 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { SystemImport("RxLibrary/GRXWriteable.h") + SystemImport("RxLibrary/GRXWriter.h"); - ::grpc::string forward_declarations = "@class GRPCProtoCall;\n\n"; + ::grpc::string forward_declarations = + "@class GRPCProtoCall;\n" + "@class GRPCUnaryProtoCall;\n" + "@class GRPCStreamingProtoCall;\n" + "@class GRPCCallOptions;\n" + "@protocol GRPCResponseHandler;\n" + "\n"; ::grpc::string class_declarations = grpc_objective_c_generator::GetAllMessageClasses(file); @@ -103,6 +109,12 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { class_imports += ImportProtoHeaders(file->dependency(i), " "); } + ::grpc::string ng_protocols; + for (int i = 0; i < file->service_count(); i++) { + const grpc::protobuf::ServiceDescriptor* service = file->service(i); + ng_protocols += grpc_objective_c_generator::GetV2Protocol(service); + } + ::grpc::string protocols; for (int i = 0; i < file->service_count(); i++) { const grpc::protobuf::ServiceDescriptor* service = file->service(i); @@ -120,9 +132,10 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { PreprocIfNot(kProtocolOnly, system_imports) + "\n" + class_declarations + "\n" + PreprocIfNot(kForwardDeclare, class_imports) + "\n" + - forward_declarations + "\n" + kNonNullBegin + "\n" + protocols + - "\n" + PreprocIfNot(kProtocolOnly, interfaces) + "\n" + - kNonNullEnd + "\n"); + forward_declarations + "\n" + kNonNullBegin + "\n" + + ng_protocols + protocols + "\n" + + PreprocIfNot(kProtocolOnly, interfaces) + "\n" + kNonNullEnd + + "\n"); } { diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 45d3526092..1a27cac2a3 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -21,6 +21,55 @@ #import "ProtoMethod.h" +@class GPBMessage; + +/** A unary-request RPC call with Protobuf. */ +@interface GRPCUnaryProtoCall : NSObject + +/** + * Users should not use this initializer directly. Call objects will be created, initialized, and + * returned to users by methods of the generated service. + */ +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + message:(GPBMessage *)message + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass; + +/** Cancel the call at best effort. */ +- (void)cancel; + +@end + +/** A client-streaming RPC call with Protobuf. */ +@interface GRPCStreamingProtoCall : NSObject + +/** + * Users should not use this initializer directly. Call objects will be created, initialized, and + * returned to users by methods of the generated service. + */ +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass; + +/** Cancel the call at best effort. */ +- (void)cancel; + +/** + * Send a message to the server. The message should be a Protobuf message which will be serialized + * internally. + */ +- (void)writeWithMessage:(GPBMessage *)message; + +/** + * Finish the RPC request and half-close the call. The server may still send messages and/or + * trailers to the client. + */ +- (void)finish; + +@end + __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC : GRPCCall diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 5dca971b08..f89c160650 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -23,9 +23,166 @@ #else #import #endif +#import #import #import +@implementation GRPCUnaryProtoCall { + GRPCStreamingProtoCall *_call; +} + +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + message:(GPBMessage *)message + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass { + if ((self = [super init])) { + _call = [[GRPCStreamingProtoCall alloc] initWithRequestOptions:requestOptions + responseHandler:handler + callOptions:callOptions + responseClass:responseClass]; + [_call writeWithMessage:message]; + [_call finish]; + } + return self; +} + +- (void)cancel { + [_call cancel]; + _call = nil; +} + +@end + +@interface GRPCStreamingProtoCall () + +@end + +@implementation GRPCStreamingProtoCall { + GRPCRequestOptions *_requestOptions; + id _handler; + GRPCCallOptions *_callOptions; + Class _responseClass; + + GRPCCall2 *_call; + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass { + if ((self = [super init])) { + _requestOptions = [requestOptions copy]; + _handler = handler; + _callOptions = [callOptions copy]; + _responseClass = responseClass; + _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + + [self start]; + } + return self; +} + +- (void)start { + _call = [[GRPCCall2 alloc] initWithRequestOptions:_requestOptions + handler:self + callOptions:_callOptions]; + [_call start]; +} + +- (void)cancel { + dispatch_async(_dispatchQueue, ^{ + if (_call) { + [_call cancel]; + _call = nil; + } + if (_handler) { + id handler = _handler; + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + }); + _handler = nil; + } + }); +} + +- (void)writeWithMessage:(GPBMessage *)message { + if (![message isKindOfClass:[GPBMessage class]]) { + [NSException raise:NSInvalidArgumentException format:@"Data must be a valid protobuf type."]; + } + + dispatch_async(_dispatchQueue, ^{ + if (_call) { + [_call writeWithData:[message data]]; + } + }); +} + +- (void)finish { + dispatch_async(_dispatchQueue, ^{ + if (_call) { + [_call finish]; + _call = nil; + } + }); +} + +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { + if (_handler) { + id handler = _handler; + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedInitialMetadata:initialMetadata]; + }); + } +} + +- (void)receivedMessage:(NSData *)message { + if (_handler) { + id handler = _handler; + NSError *error = nil; + id parsed = [_responseClass parseFromData:message error:&error]; + if (parsed) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedMessage:parsed]; + }); + } else { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:nil error:error]; + }); + handler = nil; + [_call cancel]; + _call = nil; + } + } +} + +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { + if (_handler) { + id handler = _handler; + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:trailingMetadata error:error]; + }); + _handler = nil; + } + if (_call) { + [_call cancel]; + _call = nil; + } +} + +- (dispatch_queue_t)dispatchQueue { + return _dispatchQueue; +} + +@end + static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { NSDictionary *info = @{ NSLocalizedDescriptionKey : @"Unable to parse response from the server", diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index 29c4e9be36..2105de78a3 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -21,16 +21,40 @@ @class GRPCProtoCall; @protocol GRXWriteable; @class GRXWriter; +@class GRPCCallOptions; +@class GRPCProtoCall; +@class GRPCUnaryProtoCall; +@class GRPCStreamingProtoCall; +@protocol GRPCProtoResponseCallbacks; __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoService - : NSObject - + : NSObject + + - (instancetype)initWithHost : (NSString *)host packageName - : (NSString *)packageName serviceName : (NSString *)serviceName NS_DESIGNATED_INITIALIZER; + : (NSString *)packageName serviceName : (NSString *)serviceName callOptions + : (GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithHost:(NSString *)host + packageName:(NSString *)packageName + serviceName:(NSString *)serviceName; - (GRPCProtoCall *)RPCToMethod:(NSString *)method requestsWriter:(GRXWriter *)requestsWriter responseClass:(Class)responseClass responsesWriteable:(id)responsesWriteable; + +- (GRPCUnaryProtoCall *)RPCToMethod:(NSString *)method + message:(id)message + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass; + +- (GRPCStreamingProtoCall *)RPCToMethod:(NSString *)method + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass; + @end /** diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m index 3e9cc5c0b2..6df502fb0c 100644 --- a/src/objective-c/ProtoRPC/ProtoService.m +++ b/src/objective-c/ProtoRPC/ProtoService.m @@ -18,6 +18,7 @@ #import "ProtoService.h" +#import #import #import @@ -31,6 +32,7 @@ NSString *_host; NSString *_packageName; NSString *_serviceName; + GRPCCallOptions *_callOptions; } - (instancetype)init { @@ -40,7 +42,8 @@ // Designated initializer - (instancetype)initWithHost:(NSString *)host packageName:(NSString *)packageName - serviceName:(NSString *)serviceName { + serviceName:(NSString *)serviceName + callOptions:(GRPCCallOptions *)callOptions { if (!host || !serviceName) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor serviceName can be nil."]; @@ -49,10 +52,17 @@ _host = [host copy]; _packageName = [packageName copy]; _serviceName = [serviceName copy]; + _callOptions = [callOptions copy]; } return self; } +- (instancetype)initWithHost:(NSString *)host + packageName:(NSString *)packageName + serviceName:(NSString *)serviceName { + return [self initWithHost:host packageName:packageName serviceName:serviceName callOptions:nil]; +} + - (GRPCProtoCall *)RPCToMethod:(NSString *)method requestsWriter:(GRXWriter *)requestsWriter responseClass:(Class)responseClass @@ -65,6 +75,41 @@ responseClass:responseClass responsesWriteable:responsesWriteable]; } + +- (GRPCUnaryProtoCall *)RPCToMethod:(NSString *)method + message:(id)message + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass { + GRPCProtoMethod *methodName = + [[GRPCProtoMethod alloc] initWithPackage:_packageName service:_serviceName method:method]; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:_host + path:methodName.HTTPPath + safety:GRPCCallSafetyDefault]; + return [[GRPCUnaryProtoCall alloc] initWithRequestOptions:requestOptions + message:message + responseHandler:handler + callOptions:callOptions ?: _callOptions + responseClass:responseClass]; +} + +- (GRPCStreamingProtoCall *)RPCToMethod:(NSString *)method + responseHandler:(id)handler + callOptions:(GRPCCallOptions *)callOptions + responseClass:(Class)responseClass { + GRPCProtoMethod *methodName = + [[GRPCProtoMethod alloc] initWithPackage:_packageName service:_serviceName method:method]; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:_host + path:methodName.HTTPPath + safety:GRPCCallSafetyDefault]; + return [[GRPCStreamingProtoCall alloc] initWithRequestOptions:requestOptions + responseHandler:handler + callOptions:callOptions ?: _callOptions + responseClass:responseClass]; +} + @end @implementation GRPCProtoService -- cgit v1.2.3 From e2e5c8189310841f7edd5ae8a51a616c9d93b309 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 8 Oct 2018 15:50:55 -0700 Subject: New API for GRPCCall --- include/grpc/impl/codegen/grpc_types.h | 4 + src/objective-c/GRPCClient/GRPCCall.h | 145 ++++++--- src/objective-c/GRPCClient/GRPCCall.m | 253 +++++++++++++++- src/objective-c/GRPCClient/GRPCCallOptions.h | 317 ++++++++++++++++++++ src/objective-c/GRPCClient/GRPCCallOptions.m | 431 +++++++++++++++++++++++++++ 5 files changed, 1105 insertions(+), 45 deletions(-) create mode 100644 src/objective-c/GRPCClient/GRPCCallOptions.h create mode 100644 src/objective-c/GRPCClient/GRPCCallOptions.m diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 3ce88a8264..4cf13edca9 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -347,6 +347,10 @@ typedef struct { /** If set to non zero, surfaces the user agent string to the server. User agent is surfaced by default. */ #define GRPC_ARG_SURFACE_USER_AGENT "grpc.surface_user_agent" +/** gRPC Objective-C channel pooling domain string. */ +#define GRPC_ARG_CHANNEL_POOL_DOMAIN "grpc.channel_pooling_domain" +/** gRPC Objective-C channel pooling id. */ +#define GRPC_ARG_CHANNEL_ID "grpc.channel_id" /** \} */ /** Result of a grpc call. If the caller satisfies the prerequisites of a diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index e0ef8b1391..3f6ec75c04 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -37,6 +37,10 @@ #include +#include "GRPCCallOptions.h" + +@class GRPCCallOptions; + #pragma mark gRPC errors /** Domain of NSError objects produced by gRPC. */ @@ -139,19 +143,6 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) { GRPCErrorCodeDataLoss = 15, }; -/** - * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1 - */ -typedef NS_ENUM(NSUInteger, GRPCCallSafety) { - /** Signal that there is no guarantees on how the call affects the server state. */ - GRPCCallSafetyDefault = 0, - /** Signal that the call is idempotent. gRPC is free to use PUT verb. */ - GRPCCallSafetyIdempotentRequest = 1, - /** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET - verb. */ - GRPCCallSafetyCacheableRequest = 2, -}; - /** * Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by * the server. @@ -159,23 +150,117 @@ typedef NS_ENUM(NSUInteger, GRPCCallSafety) { extern id const kGRPCHeadersKey; extern id const kGRPCTrailersKey; +/** An object can implement this protocol to receive responses from server from a call. */ +@protocol GRPCResponseHandler +@optional +/** Issued when initial metadata is received from the server. */ +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; +/** + * Issued when a message is received from the server. The message may be raw data from the server + * (when using \a GRPCCall2 directly) or deserialized proto object (when using \a ProtoRPC). + */ +- (void)receivedMessage:(id)message; +/** + * Issued when a call finished. If the call finished successfully, \a error is nil and \a + * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error + * is non-nil and contains the corresponding error information, including gRPC error codes and + * error descriptions. + */ +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error; + +/** + * All the responses must be issued to a user-provided dispatch queue. This property specifies the + * dispatch queue to be used for issuing the notifications. + */ +@property(atomic, readonly) dispatch_queue_t dispatchQueue; + +@end + +/** + * Call related parameters. These parameters are automatically specified by Protobuf. If directly + * using the \a GRPCCall2 class, users should specify these parameters manually. + */ +@interface GRPCRequestOptions : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Initialize with all properties. */ +- (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety; + +/** The host serving the RPC service. */ +@property(copy, readonly) NSString *host; +/** The path to the RPC call. */ +@property(copy, readonly) NSString *path; +/** + * Specify whether the call is idempotent or cachable. gRPC may select different HTTP verbs for the + * call based on this information. + */ +@property(readonly) GRPCCallSafety safety; + +@end + #pragma mark GRPCCall -/** Represents a single gRPC remote call. */ -@interface GRPCCall : GRXWriter +/** + * A \a GRPCCall2 object represents an RPC call. + */ +@interface GRPCCall2 : NSObject + +- (instancetype)init NS_UNAVAILABLE; /** - * The authority for the RPC. If nil, the default authority will be used. This property must be nil - * when Cronet transport is enabled. + * Designated initializer for a call. + * \param requestOptions Protobuf generated parameters for the call. + * \param handler The object to which responses should be issed. + * \param callOptions Options for the call. */ -@property(atomic, copy, readwrite) NSString *serverName; +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + handler:(id)handler + callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; +/** + * Convevience initializer for a call that uses default call options. + */ +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + handler:(id)handler; /** - * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to - * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed - * within \a timeout seconds. A negative value is not allowed. + * Starts the call. Can only be called once. */ -@property NSTimeInterval timeout; +- (void)start; + +/** + * Cancel the request of this call at best effort; notifies the server that the RPC should be + * cancelled, and issue callback to the user with an error code CANCELED if the call is not + * finished. + */ +- (void)cancel; + +/** + * Send a message to the server. Data are sent as raw bytes in gRPC message frames. + */ +- (void)writeWithData:(NSData *)data; + +/** + * Finish the RPC request and half-close the call. The server may still send messages and/or + * trailers to the client. + */ -(void)finish; + +/** + * Get a copy of the original call options. + */ +@property(readonly, copy) GRPCCallOptions *callOptions; + +/** Get a copy of the original request options. */ +@property(readonly, copy) GRPCRequestOptions *requestOptions; + +@end + +/** + * This interface is deprecated. Please use \a GRPCcall2. + * + * Represents a single gRPC remote call. + */ +@interface GRPCCall : GRXWriter /** * The container of the request headers of an RPC conforms to this protocol, which is a subset of @@ -236,7 +321,7 @@ extern id const kGRPCTrailersKey; */ - (instancetype)initWithHost:(NSString *)host path:(NSString *)path - requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER; + requestsWriter:(GRXWriter *)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and @@ -245,21 +330,13 @@ extern id const kGRPCTrailersKey; - (void)cancel; /** - * Set the call flag for a specific host path. - * - * Host parameter should not contain the scheme (http:// or https://), only the name or IP addr - * and the port number, for example @"localhost:5050". + * The following methods are deprecated. */ + (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; - -/** - * Set the dispatch queue to be used for callbacks. - * - * This configuration is only effective before the call starts. - */ +@property(atomic, copy, readwrite) NSString *serverName; +@property NSTimeInterval timeout; - (void)setResponseDispatchQueue:(dispatch_queue_t)queue; -// TODO(jcanizales): Let specify a deadline. As a category of GRXWriter? @end #pragma mark Backwards compatibiity diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 084fbdeb49..519f91e522 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -20,13 +20,16 @@ #import "GRPCCall+OAuth2.h" +#import #import #import +#import #include #include -#import "private/GRPCConnectivityMonitor.h" +#import "GRPCCallOptions.h" #import "private/GRPCHost.h" +#import "private/GRPCConnectivityMonitor.h" #import "private/GRPCRequestHeaders.h" #import "private/GRPCWrappedCall.h" #import "private/NSData+GRPC.h" @@ -52,6 +55,165 @@ const char *kCFStreamVarName = "grpc_cfstream"; @property(atomic, strong) NSDictionary *responseHeaders; @property(atomic, strong) NSDictionary *responseTrailers; @property(atomic) BOOL isWaitingForToken; + +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + callSafety:(GRPCCallSafety)safety + requestsWriter:(GRXWriter *)requestsWriter + callOptions:(GRPCCallOptions *)callOptions; + +@end + +@implementation GRPCRequestOptions + +- (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { + if ((self = [super init])) { + _host = host; + _path = path; + _safety = safety; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + GRPCRequestOptions *request = + [[GRPCRequestOptions alloc] initWithHost:[_host copy] path:[_path copy] safety:_safety]; + + return request; +} + +@end + +@implementation GRPCCall2 { + GRPCCallOptions *_callOptions; + id _handler; + + GRPCCall *_call; + BOOL _initialMetadataPublished; + GRXBufferedPipe *_pipe; + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + handler:(id)handler + callOptions:(GRPCCallOptions *)callOptions { + if (!requestOptions || !requestOptions.host || !requestOptions.path) { + [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; + } + + if ((self = [super init])) { + _requestOptions = [requestOptions copy]; + _callOptions = [callOptions copy]; + _handler = handler; + _initialMetadataPublished = NO; + _pipe = [GRXBufferedPipe pipe]; + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } + + return self; +} + +- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + handler:(id)handler { + return [self initWithRequestOptions:requestOptions handler:handler callOptions:nil]; +} + +- (void)start { + dispatch_async(_dispatchQueue, ^{ + if (!self->_callOptions) { + self->_callOptions = [[GRPCCallOptions alloc] init]; + } + + self->_call = [[GRPCCall alloc] initWithHost:self->_requestOptions.host + path:self->_requestOptions.path + callSafety:self->_requestOptions.safety + requestsWriter:self->_pipe + callOptions:self->_callOptions]; + if (self->_callOptions.initialMetadata) { + [self->_call.requestHeaders addEntriesFromDictionary:self->_callOptions.initialMetadata]; + } + id responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(id value) { + dispatch_async(self->_dispatchQueue, ^{ + if (self->_handler) { + id handler = self->_handler; + NSDictionary *headers = nil; + if (!self->_initialMetadataPublished) { + headers = self->_call.responseHeaders; + self->_initialMetadataPublished = YES; + } + if (headers) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedInitialMetadata:headers]; + }); + } + if (value) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedMessage:value]; + }); + } + } + }); + } + completionHandler:^(NSError *errorOrNil) { + dispatch_async(self->_dispatchQueue, ^{ + if (self->_handler) { + id handler = self->_handler; + NSDictionary *headers = nil; + if (!self->_initialMetadataPublished) { + headers = self->_call.responseHeaders; + self->_initialMetadataPublished = YES; + } + if (headers) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedInitialMetadata:headers]; + }); + } + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; + }); + } + }); + }]; + [self->_call startWithWriteable:responseWriteable]; + }); +} + +- (void)cancel { + dispatch_async(_dispatchQueue, ^{ + if (self->_call) { + [self->_call cancel]; + self->_call = nil; + } + if (self->_handler) { + id handler = self->_handler; + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + }); + self->_handler = nil; + } + }); +} + +- (void)writeWithData:(NSData *)data { + dispatch_async(_dispatchQueue, ^{ + [self->_pipe writeValue:data]; + }); +} + +- (void)finish { + dispatch_async(_dispatchQueue, ^{ + if (self->_call) { + [self->_pipe writesFinishedWithError:nil]; + } + }); +} + @end // The following methods of a C gRPC call object aren't reentrant, and thus @@ -75,6 +237,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; NSString *_host; NSString *_path; + GRPCCallSafety _callSafety; + GRPCCallOptions *_callOptions; GRPCWrappedCall *_wrappedCall; GRPCConnectivityMonitor *_connectivityMonitor; @@ -113,6 +277,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Whether the call is finished. If it is, should not call finishWithError again. BOOL _finished; + + // The OAuth2 token fetched from a token provider. + NSString *_fetchedOauth2AccessToken; } @synthesize state = _state; @@ -156,6 +323,18 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithHost:(NSString *)host path:(NSString *)path requestsWriter:(GRXWriter *)requestWriter { + return [self initWithHost:host + path:path + callSafety:GRPCCallSafetyDefault + requestsWriter:requestWriter + callOptions:nil]; +} + +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + callSafety:(GRPCCallSafety)safety + requestsWriter:(GRXWriter *)requestWriter + callOptions:(GRPCCallOptions *)callOptions { if (!host || !path) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; } @@ -166,6 +345,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; if ((self = [super init])) { _host = [host copy]; _path = [path copy]; + _callSafety = safety; + _callOptions = [callOptions copy]; // Serial queue to invoke the non-reentrant methods of the grpc_call object. _callQueue = dispatch_queue_create("io.grpc.call", NULL); @@ -317,11 +498,36 @@ const char *kCFStreamVarName = "grpc_cfstream"; #pragma mark Send headers -- (void)sendHeaders:(NSDictionary *)headers { +- (void)sendHeaders { + // TODO (mxyan): Remove after deprecated methods are removed + uint32_t callSafetyFlags; + switch (_callSafety) { + case GRPCCallSafetyDefault: + callSafetyFlags = 0; + break; + case GRPCCallSafetyIdempotentRequest: + callSafetyFlags = GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST; + break; + case GRPCCallSafetyCacheableRequest: + callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; + break; + default: + [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; + } + uint32_t callFlag = callSafetyFlags; + + NSMutableDictionary *headers = _requestHeaders; + if (_fetchedOauth2AccessToken != nil) { + headers[@"authorization"] = [kBearerPrefix stringByAppendingString:_fetchedOauth2AccessToken]; + } else if (_callOptions.oauth2AccessToken != nil) { + headers[@"authorization"] = + [kBearerPrefix stringByAppendingString:_callOptions.oauth2AccessToken]; + } + // TODO(jcanizales): Add error handlers for async failures GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc] initWithMetadata:headers - flags:[GRPCCall callFlagsForHost:_host path:_path] + flags:callFlag handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA if (!_unaryCall) { [_wrappedCall startBatchWithOperations:@[ op ]]; @@ -458,13 +664,10 @@ const char *kCFStreamVarName = "grpc_cfstream"; _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; - _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host - serverName:_serverName - path:_path - timeout:_timeout]; + _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions]; NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?"); - [self sendHeaders:_requestHeaders]; + [self sendHeaders]; [self invokeCall]; // Connectivity monitor is not required for CFStream @@ -486,15 +689,43 @@ const char *kCFStreamVarName = "grpc_cfstream"; // that the life of the instance is determined by this retain cycle. _retainSelf = self; - if (self.tokenProvider != nil) { + if (_callOptions == nil) { + GRPCMutableCallOptions *callOptions; + if ([GRPCHost isHostConfigured:_host]) { + GRPCHost *hostConfig = [GRPCHost hostWithAddress:_host]; + callOptions = hostConfig.callOptions; + } else { + callOptions = [[GRPCMutableCallOptions alloc] init]; + } + if (_serverName != nil) { + callOptions.serverAuthority = _serverName; + } + if (_timeout != 0) { + callOptions.timeout = _timeout; + } + uint32_t callFlags = [GRPCCall callFlagsForHost:_host path:_path]; + if (callFlags != 0) { + if (callFlags == GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) { + _callSafety = GRPCCallSafetyIdempotentRequest; + } else if (callFlags == GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) { + _callSafety = GRPCCallSafetyCacheableRequest; + } + } + + id tokenProvider = self.tokenProvider; + if (tokenProvider != nil) { + callOptions.authTokenProvider = tokenProvider; + } + _callOptions = callOptions; + } + if (_callOptions.authTokenProvider != nil) { self.isWaitingForToken = YES; __weak typeof(self) weakSelf = self; [self.tokenProvider getTokenWithHandler:^(NSString *token) { typeof(self) strongSelf = weakSelf; if (strongSelf && strongSelf.isWaitingForToken) { if (token) { - NSString *t = [kBearerPrefix stringByAppendingString:token]; - strongSelf.requestHeaders[kAuthorizationHeader] = t; + strongSelf->_fetchedOauth2AccessToken = token; } [strongSelf startCallWithWriteable:writeable]; strongSelf.isWaitingForToken = NO; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h new file mode 100644 index 0000000000..75b320ca6d --- /dev/null +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -0,0 +1,317 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +/** + * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1 + */ +typedef NS_ENUM(NSUInteger, GRPCCallSafety) { + /** Signal that there is no guarantees on how the call affects the server state. */ + GRPCCallSafetyDefault = 0, + /** Signal that the call is idempotent. gRPC is free to use PUT verb. */ + GRPCCallSafetyIdempotentRequest = 1, + /** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET + verb. */ + GRPCCallSafetyCacheableRequest = 2, +}; + +// Compression algorithm to be used by a gRPC call +typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) { + GRPCCompressNone = 0, + GRPCCompressDeflate, + GRPCCompressGzip, + GRPCStreamCompressGzip, +}; + +// The transport to be used by a gRPC call +typedef NS_ENUM(NSInteger, GRPCTransportType) { + // gRPC internal HTTP/2 stack with BoringSSL + GRPCTransportTypeDefault = 0, + // Cronet stack + GRPCTransportTypeCronet, + // Insecure channel. FOR TEST ONLY! + GRPCTransportTypeInsecure, +}; + +@protocol GRPCAuthorizationProtocol +- (void)getTokenWithHandler:(void (^)(NSString *token))hander; +@end + +@interface GRPCCallOptions : NSObject + +// Call parameters +/** + * The authority for the RPC. If nil, the default authority will be used. + * + * Note: This property must be nil when Cronet transport is enabled. + * Note: This property cannot be used to validate a self-signed server certificate. It control the + * :authority header field of the call and performs an extra check that server's certificate + * matches the :authority header. + */ +@property(readonly) NSString *serverAuthority; + +/** + * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to + * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed + * within \a timeout seconds. A negative value is not allowed. + */ +@property(readonly) NSTimeInterval timeout; + +// OAuth2 parameters. Users of gRPC may specify one of the following two parameters. + +/** + * The OAuth2 access token string. The string is prefixed with "Bearer " then used as value of the + * request's "authorization" header field. This parameter should not be used simultaneously with + * \a authTokenProvider. + */ +@property(copy, readonly) NSString *oauth2AccessToken; + +/** + * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when + * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken. + */ +@property(readonly) id authTokenProvider; + +/** + * Initial metadata key-value pairs that should be included in the request. + */ +@property(copy, readwrite) NSDictionary *initialMetadata; + +// Channel parameters; take into account of channel signature. + +/** + * Custom string that is prefixed to a request's user-agent header field before gRPC's internal + * user-agent string. + */ +@property(copy, readonly) NSString *userAgentPrefix; + +/** + * The size limit for the response received from server. If it is exceeded, an error with status + * code GRPCErrorCodeResourceExhausted is returned. + */ +@property(readonly) NSUInteger responseSizeLimit; + +/** + * The compression algorithm to be used by the gRPC call. For more details refer to + * https://github.com/grpc/grpc/blob/master/doc/compression.md + */ +@property(readonly) GRPCCompressAlgorithm compressAlgorithm; + +/** + * Enable/Disable gRPC call's retry feature. The default is enabled. For details of this feature + * refer to + * https://github.com/grpc/proposal/blob/master/A6-client-retries.md + */ +@property(readonly) BOOL enableRetry; + +/** + * HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two + * PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the + * call should wait for PING ACK. If PING ACK is not received after this period, the call fails. + */ +@property(readonly) NSTimeInterval keepaliveInterval; +@property(readonly) NSTimeInterval keepaliveTimeout; + +// Parameters for connection backoff. For details of gRPC's backoff behavior, refer to +// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md +@property(readonly) NSTimeInterval connectMinTimeout; +@property(readonly) NSTimeInterval connectInitialBackoff; +@property(readonly) NSTimeInterval connectMaxBackoff; + +/** + * Specify channel args to be used for this call. For a list of channel args available, see + * grpc/grpc_types.h + */ +@property(copy, readonly) NSDictionary *additionalChannelArgs; + +// Parameters for SSL authentication. + +/** + * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default + * root certificates. + */ +@property(copy, readonly) NSString *pemRootCert; + +/** + * PEM format private key for client authentication, if required by the server. + */ +@property(copy, readonly) NSString *pemPrivateKey; + +/** + * PEM format certificate chain for client authentication, if required by the server. + */ +@property(copy, readonly) NSString *pemCertChain; + +/** + * Select the transport type to be used for this call. + */ +@property(readonly) GRPCTransportType transportType; + +/** + * Override the hostname during the TLS hostname validation process. + */ +@property(copy, readonly) NSString *hostNameOverride; + +/** + * Parameter used for internal logging. + */ +@property(readonly) id logContext; + +/** + * A string that specify the domain where channel is being cached. Channels with different domains + * will not get cached to the same connection. + */ +@property(copy, readonly) NSString *channelPoolDomain; + +/** + * Channel id allows a call to force creating a new channel (connection) rather than using a cached + * channel. Calls using distinct channelId will not get cached to the same connection. + */ +@property(readonly) NSUInteger channelId; + +@end + +@interface GRPCMutableCallOptions : GRPCCallOptions + +// Call parameters +/** + * The authority for the RPC. If nil, the default authority will be used. + * + * Note: This property must be nil when Cronet transport is enabled. + * Note: This property cannot be used to validate a self-signed server certificate. It control the + * :authority header field of the call and performs an extra check that server's certificate + * matches the :authority header. + */ +@property(readwrite) NSString *serverAuthority; + +/** + * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to + * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed + * within \a timeout seconds. A negative value is not allowed. + */ +@property(readwrite) NSTimeInterval timeout; + +// OAuth2 parameters. Users of gRPC may specify one of the following two parameters. + +/** + * The OAuth2 access token string. The string is prefixed with "Bearer " then used as value of the + * request's "authorization" header field. This parameter should not be used simultaneously with + * \a authTokenProvider. + */ +@property(copy, readwrite) NSString *oauth2AccessToken; + +/** + * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when + * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken. + */ +@property(readwrite) id authTokenProvider; + +// Channel parameters; take into account of channel signature. + +/** + * Custom string that is prefixed to a request's user-agent header field before gRPC's internal + * user-agent string. + */ +@property(copy, readwrite) NSString *userAgentPrefix; + +/** + * The size limit for the response received from server. If it is exceeded, an error with status + * code GRPCErrorCodeResourceExhausted is returned. + */ +@property(readwrite) NSUInteger responseSizeLimit; + +/** + * The compression algorithm to be used by the gRPC call. For more details refer to + * https://github.com/grpc/grpc/blob/master/doc/compression.md + */ +@property(readwrite) GRPCCompressAlgorithm compressAlgorithm; + +/** + * Enable/Disable gRPC call's retry feature. The default is enabled. For details of this feature + * refer to + * https://github.com/grpc/proposal/blob/master/A6-client-retries.md + */ +@property(readwrite) BOOL enableRetry; + +/** + * HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two + * PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the + * call should wait for PING ACK. If PING ACK is not received after this period, the call fails. + */ +@property(readwrite) NSTimeInterval keepaliveInterval; +@property(readwrite) NSTimeInterval keepaliveTimeout; + +// Parameters for connection backoff. For details of gRPC's backoff behavior, refer to +// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md +@property(readwrite) NSTimeInterval connectMinTimeout; +@property(readwrite) NSTimeInterval connectInitialBackoff; +@property(readwrite) NSTimeInterval connectMaxBackoff; + +/** + * Specify channel args to be used for this call. For a list of channel args available, see + * grpc/grpc_types.h + */ +@property(copy, readwrite) NSDictionary *additionalChannelArgs; + +// Parameters for SSL authentication. + +/** + * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default + * root certificates. + */ +@property(copy, readwrite) NSString *pemRootCert; + +/** + * PEM format private key for client authentication, if required by the server. + */ +@property(copy, readwrite) NSString *pemPrivateKey; + +/** + * PEM format certificate chain for client authentication, if required by the server. + */ +@property(copy, readwrite) NSString *pemCertChain; + +/** + * Select the transport type to be used for this call. + */ +@property(readwrite) GRPCTransportType transportType; + +/** + * Override the hostname during the TLS hostname validation process. + */ +@property(copy, readwrite) NSString *hostNameOverride; + +/** + * Parameter used for internal logging. + */ +@property(copy, readwrite) id logContext; + +/** + * A string that specify the domain where channel is being cached. Channels with different domains + * will not get cached to the same connection. + */ +@property(copy, readwrite) NSString *channelPoolDomain; + +/** + * Channel id allows a call to force creating a new channel (connection) rather than using a cached + * channel. Calls using distinct channelId will not get cached to the same connection. + */ +@property(readwrite) NSUInteger channelId; + +@end diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m new file mode 100644 index 0000000000..ee76c2a642 --- /dev/null +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -0,0 +1,431 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GRPCCallOptions.h" + +static NSString *const kDefaultServerAuthority = nil; +static const NSTimeInterval kDefaultTimeout = 0; +static NSDictionary *const kDefaultInitialMetadata = nil; +static NSString *const kDefaultUserAgentPrefix = nil; +static const NSUInteger kDefaultResponseSizeLimit = 0; +static const GRPCCompressAlgorithm kDefaultCompressAlgorithm = GRPCCompressNone; +static const BOOL kDefaultEnableRetry = YES; +static const NSTimeInterval kDefaultKeepaliveInterval = 0; +static const NSTimeInterval kDefaultKeepaliveTimeout = 0; +static const NSTimeInterval kDefaultConnectMinTimeout = 0; +static const NSTimeInterval kDefaultConnectInitialBackoff = 0; +static const NSTimeInterval kDefaultConnectMaxBackoff = 0; +static NSDictionary *const kDefaultAdditionalChannelArgs = nil; +static NSString *const kDefaultPemRootCert = nil; +static NSString *const kDefaultPemPrivateKey = nil; +static NSString *const kDefaultPemCertChain = nil; +static NSString *const kDefaultOauth2AccessToken = nil; +static const id kDefaultAuthTokenProvider = nil; +static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeDefault; +static NSString *const kDefaultHostNameOverride = nil; +static const id kDefaultLogContext = nil; +static NSString *kDefaultChannelPoolDomain = nil; +static NSUInteger kDefaultChannelId = 0; + +@implementation GRPCCallOptions { + @protected + NSString *_serverAuthority; + NSTimeInterval _timeout; + NSString *_oauth2AccessToken; + id _authTokenProvider; + NSDictionary *_initialMetadata; + NSString *_userAgentPrefix; + NSUInteger _responseSizeLimit; + GRPCCompressAlgorithm _compressAlgorithm; + BOOL _enableRetry; + NSTimeInterval _keepaliveInterval; + NSTimeInterval _keepaliveTimeout; + NSTimeInterval _connectMinTimeout; + NSTimeInterval _connectInitialBackoff; + NSTimeInterval _connectMaxBackoff; + NSDictionary *_additionalChannelArgs; + NSString *_pemRootCert; + NSString *_pemPrivateKey; + NSString *_pemCertChain; + GRPCTransportType _transportType; + NSString *_hostNameOverride; + id _logContext; + NSString *_channelPoolDomain; + NSUInteger _channelId; +} + +@synthesize serverAuthority = _serverAuthority; +@synthesize timeout = _timeout; +@synthesize oauth2AccessToken = _oauth2AccessToken; +@synthesize authTokenProvider = _authTokenProvider; +@synthesize initialMetadata = _initialMetadata; +@synthesize userAgentPrefix = _userAgentPrefix; +@synthesize responseSizeLimit = _responseSizeLimit; +@synthesize compressAlgorithm = _compressAlgorithm; +@synthesize enableRetry = _enableRetry; +@synthesize keepaliveInterval = _keepaliveInterval; +@synthesize keepaliveTimeout = _keepaliveTimeout; +@synthesize connectMinTimeout = _connectMinTimeout; +@synthesize connectInitialBackoff = _connectInitialBackoff; +@synthesize connectMaxBackoff = _connectMaxBackoff; +@synthesize additionalChannelArgs = _additionalChannelArgs; +@synthesize pemRootCert = _pemRootCert; +@synthesize pemPrivateKey = _pemPrivateKey; +@synthesize pemCertChain = _pemCertChain; +@synthesize transportType = _transportType; +@synthesize hostNameOverride = _hostNameOverride; +@synthesize logContext = _logContext; +@synthesize channelPoolDomain = _channelPoolDomain; +@synthesize channelId = _channelId; + +- (instancetype)init { + return [self initWithServerAuthority:kDefaultServerAuthority + timeout:kDefaultTimeout + oauth2AccessToken:kDefaultOauth2AccessToken + authTokenProvider:kDefaultAuthTokenProvider + initialMetadata:kDefaultInitialMetadata + userAgentPrefix:kDefaultUserAgentPrefix + responseSizeLimit:kDefaultResponseSizeLimit + compressAlgorithm:kDefaultCompressAlgorithm + enableRetry:kDefaultEnableRetry + keepaliveInterval:kDefaultKeepaliveInterval + keepaliveTimeout:kDefaultKeepaliveTimeout + connectMinTimeout:kDefaultConnectMinTimeout + connectInitialBackoff:kDefaultConnectInitialBackoff + connectMaxBackoff:kDefaultConnectMaxBackoff + additionalChannelArgs:kDefaultAdditionalChannelArgs + pemRootCert:kDefaultPemRootCert + pemPrivateKey:kDefaultPemPrivateKey + pemCertChain:kDefaultPemCertChain + transportType:kDefaultTransportType + hostNameOverride:kDefaultHostNameOverride + logContext:kDefaultLogContext + channelPoolDomain:kDefaultChannelPoolDomain + channelId:kDefaultChannelId]; +} + +- (instancetype)initWithServerAuthority:(NSString *)serverAuthority + timeout:(NSTimeInterval)timeout + oauth2AccessToken:(NSString *)oauth2AccessToken + authTokenProvider:(id)authTokenProvider + initialMetadata:(NSDictionary *)initialMetadata + userAgentPrefix:(NSString *)userAgentPrefix + responseSizeLimit:(NSUInteger)responseSizeLimit + compressAlgorithm:(GRPCCompressAlgorithm)compressAlgorithm + enableRetry:(BOOL)enableRetry + keepaliveInterval:(NSTimeInterval)keepaliveInterval + keepaliveTimeout:(NSTimeInterval)keepaliveTimeout + connectMinTimeout:(NSTimeInterval)connectMinTimeout + connectInitialBackoff:(NSTimeInterval)connectInitialBackoff + connectMaxBackoff:(NSTimeInterval)connectMaxBackoff + additionalChannelArgs:(NSDictionary *)additionalChannelArgs + pemRootCert:(NSString *)pemRootCert + pemPrivateKey:(NSString *)pemPrivateKey + pemCertChain:(NSString *)pemCertChain + transportType:(GRPCTransportType)transportType + hostNameOverride:(NSString *)hostNameOverride + logContext:(id)logContext + channelPoolDomain:(NSString *)channelPoolDomain + channelId:(NSUInteger)channelId { + if ((self = [super init])) { + _serverAuthority = serverAuthority; + _timeout = timeout; + _oauth2AccessToken = oauth2AccessToken; + _authTokenProvider = authTokenProvider; + _initialMetadata = initialMetadata; + _userAgentPrefix = userAgentPrefix; + _responseSizeLimit = responseSizeLimit; + _compressAlgorithm = compressAlgorithm; + _enableRetry = enableRetry; + _keepaliveInterval = keepaliveInterval; + _keepaliveTimeout = keepaliveTimeout; + _connectMinTimeout = connectMinTimeout; + _connectInitialBackoff = connectInitialBackoff; + _connectMaxBackoff = connectMaxBackoff; + _additionalChannelArgs = additionalChannelArgs; + _pemRootCert = pemRootCert; + _pemPrivateKey = pemPrivateKey; + _pemCertChain = pemCertChain; + _transportType = transportType; + _hostNameOverride = hostNameOverride; + _logContext = logContext; + _channelPoolDomain = channelPoolDomain; + _channelId = channelId; + } + return self; +} + +- (nonnull id)copyWithZone:(NSZone *)zone { + GRPCCallOptions *newOptions = + [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority + timeout:_timeout + oauth2AccessToken:_oauth2AccessToken + authTokenProvider:_authTokenProvider + initialMetadata:_initialMetadata + userAgentPrefix:_userAgentPrefix + responseSizeLimit:_responseSizeLimit + compressAlgorithm:_compressAlgorithm + enableRetry:_enableRetry + keepaliveInterval:_keepaliveInterval + keepaliveTimeout:_keepaliveTimeout + connectMinTimeout:_connectMinTimeout + connectInitialBackoff:_connectInitialBackoff + connectMaxBackoff:_connectMaxBackoff + additionalChannelArgs:[_additionalChannelArgs copy] + pemRootCert:_pemRootCert + pemPrivateKey:_pemPrivateKey + pemCertChain:_pemCertChain + transportType:_transportType + hostNameOverride:_hostNameOverride + logContext:_logContext + channelPoolDomain:_channelPoolDomain + channelId:_channelId]; + return newOptions; +} + +- (nonnull id)mutableCopyWithZone:(NSZone *)zone { + GRPCMutableCallOptions *newOptions = [[GRPCMutableCallOptions allocWithZone:zone] + initWithServerAuthority:_serverAuthority + timeout:_timeout + oauth2AccessToken:_oauth2AccessToken + authTokenProvider:_authTokenProvider + initialMetadata:_initialMetadata + userAgentPrefix:_userAgentPrefix + responseSizeLimit:_responseSizeLimit + compressAlgorithm:_compressAlgorithm + enableRetry:_enableRetry + keepaliveInterval:_keepaliveInterval + keepaliveTimeout:_keepaliveTimeout + connectMinTimeout:_connectMinTimeout + connectInitialBackoff:_connectInitialBackoff + connectMaxBackoff:_connectMaxBackoff + additionalChannelArgs:[_additionalChannelArgs copy] + pemRootCert:_pemRootCert + pemPrivateKey:_pemPrivateKey + pemCertChain:_pemCertChain + transportType:_transportType + hostNameOverride:_hostNameOverride + logContext:_logContext + channelPoolDomain:_channelPoolDomain + channelId:_channelId]; + return newOptions; +} + +@end + +@implementation GRPCMutableCallOptions + +@dynamic serverAuthority; +@dynamic timeout; +@dynamic oauth2AccessToken; +@dynamic authTokenProvider; +@dynamic initialMetadata; +@dynamic userAgentPrefix; +@dynamic responseSizeLimit; +@dynamic compressAlgorithm; +@dynamic enableRetry; +@dynamic keepaliveInterval; +@dynamic keepaliveTimeout; +@dynamic connectMinTimeout; +@dynamic connectInitialBackoff; +@dynamic connectMaxBackoff; +@dynamic additionalChannelArgs; +@dynamic pemRootCert; +@dynamic pemPrivateKey; +@dynamic pemCertChain; +@dynamic transportType; +@dynamic hostNameOverride; +@dynamic logContext; +@dynamic channelPoolDomain; +@dynamic channelId; + +- (instancetype)init { + return [self initWithServerAuthority:kDefaultServerAuthority + timeout:kDefaultTimeout + oauth2AccessToken:kDefaultOauth2AccessToken + authTokenProvider:kDefaultAuthTokenProvider + initialMetadata:kDefaultInitialMetadata + userAgentPrefix:kDefaultUserAgentPrefix + responseSizeLimit:kDefaultResponseSizeLimit + compressAlgorithm:kDefaultCompressAlgorithm + enableRetry:kDefaultEnableRetry + keepaliveInterval:kDefaultKeepaliveInterval + keepaliveTimeout:kDefaultKeepaliveTimeout + connectMinTimeout:kDefaultConnectMinTimeout + connectInitialBackoff:kDefaultConnectInitialBackoff + connectMaxBackoff:kDefaultConnectMaxBackoff + additionalChannelArgs:kDefaultAdditionalChannelArgs + pemRootCert:kDefaultPemRootCert + pemPrivateKey:kDefaultPemPrivateKey + pemCertChain:kDefaultPemCertChain + transportType:kDefaultTransportType + hostNameOverride:kDefaultHostNameOverride + logContext:kDefaultLogContext + channelPoolDomain:kDefaultChannelPoolDomain + channelId:kDefaultChannelId]; +} + +- (nonnull id)copyWithZone:(NSZone *)zone { + GRPCCallOptions *newOptions = + [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority + timeout:_timeout + oauth2AccessToken:_oauth2AccessToken + authTokenProvider:_authTokenProvider + initialMetadata:_initialMetadata + userAgentPrefix:_userAgentPrefix + responseSizeLimit:_responseSizeLimit + compressAlgorithm:_compressAlgorithm + enableRetry:_enableRetry + keepaliveInterval:_keepaliveInterval + keepaliveTimeout:_keepaliveTimeout + connectMinTimeout:_connectMinTimeout + connectInitialBackoff:_connectInitialBackoff + connectMaxBackoff:_connectMaxBackoff + additionalChannelArgs:[_additionalChannelArgs copy] + pemRootCert:_pemRootCert + pemPrivateKey:_pemPrivateKey + pemCertChain:_pemCertChain + transportType:_transportType + hostNameOverride:_hostNameOverride + logContext:_logContext + channelPoolDomain:_channelPoolDomain + channelId:_channelId]; + return newOptions; +} + +- (nonnull id)mutableCopyWithZone:(NSZone *)zone { + GRPCMutableCallOptions *newOptions = [[GRPCMutableCallOptions allocWithZone:zone] + initWithServerAuthority:_serverAuthority + timeout:_timeout + oauth2AccessToken:_oauth2AccessToken + authTokenProvider:_authTokenProvider + initialMetadata:_initialMetadata + userAgentPrefix:_userAgentPrefix + responseSizeLimit:_responseSizeLimit + compressAlgorithm:_compressAlgorithm + enableRetry:_enableRetry + keepaliveInterval:_keepaliveInterval + keepaliveTimeout:_keepaliveTimeout + connectMinTimeout:_connectMinTimeout + connectInitialBackoff:_connectInitialBackoff + connectMaxBackoff:_connectMaxBackoff + additionalChannelArgs:[_additionalChannelArgs copy] + pemRootCert:_pemRootCert + pemPrivateKey:_pemPrivateKey + pemCertChain:_pemCertChain + transportType:_transportType + hostNameOverride:_hostNameOverride + logContext:_logContext + channelPoolDomain:_channelPoolDomain + channelId:_channelId]; + return newOptions; +} + +- (void)setServerAuthority:(NSString *)serverAuthority { + _serverAuthority = serverAuthority; +} + +- (void)setTimeout:(NSTimeInterval)timeout { + _timeout = timeout; +} + +- (void)setOauth2AccessToken:(NSString *)oauth2AccessToken { + _oauth2AccessToken = oauth2AccessToken; +} + +- (void)setAuthTokenProvider:(id)authTokenProvider { + _authTokenProvider = authTokenProvider; +} + +- (void)setInitialMetadata:(NSDictionary *)initialMetadata { + _initialMetadata = initialMetadata; +} + +- (void)setUserAgentPrefix:(NSString *)userAgentPrefix { + _userAgentPrefix = userAgentPrefix; +} + +- (void)setResponseSizeLimit:(NSUInteger)responseSizeLimit { + _responseSizeLimit = responseSizeLimit; +} + +- (void)setCompressAlgorithm:(GRPCCompressAlgorithm)compressAlgorithm { + _compressAlgorithm = compressAlgorithm; +} + +- (void)setEnableRetry:(BOOL)enableRetry { + _enableRetry = enableRetry; +} + +- (void)setKeepaliveInterval:(NSTimeInterval)keepaliveInterval { + _keepaliveInterval = keepaliveInterval; +} + +- (void)setKeepaliveTimeout:(NSTimeInterval)keepaliveTimeout { + _keepaliveTimeout = keepaliveTimeout; +} + +- (void)setConnectMinTimeout:(NSTimeInterval)connectMinTimeout { + _connectMinTimeout = connectMinTimeout; +} + +- (void)setConnectInitialBackoff:(NSTimeInterval)connectInitialBackoff { + _connectInitialBackoff = connectInitialBackoff; +} + +- (void)setConnectMaxBackoff:(NSTimeInterval)connectMaxBackoff { + _connectMaxBackoff = connectMaxBackoff; +} + +- (void)setAdditionalChannelArgs:(NSDictionary *)additionalChannelArgs { + _additionalChannelArgs = additionalChannelArgs; +} + +- (void)setPemRootCert:(NSString *)pemRootCert { + _pemRootCert = pemRootCert; +} + +- (void)setPemPrivateKey:(NSString *)pemPrivateKey { + _pemPrivateKey = pemPrivateKey; +} + +- (void)setPemCertChain:(NSString *)pemCertChain { + _pemCertChain = pemCertChain; +} + +- (void)setTransportType:(GRPCTransportType)transportType { + _transportType = transportType; +} + +- (void)setHostNameOverride:(NSString *)hostNameOverride { + _hostNameOverride = hostNameOverride; +} + +- (void)setLogContext:(id)logContext { + _logContext = logContext; +} + +- (void)setChannelPoolDomain:(NSString *)channelPoolDomain { + _channelPoolDomain = channelPoolDomain; +} + +- (void)setChannelId:(NSUInteger)channelId { + _channelId = channelId; +} + +@end -- cgit v1.2.3 From 0fd4727defda5f8bef106a1f3b59263886b9b6c6 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 8 Oct 2018 15:51:39 -0700 Subject: deprecated old API --- src/objective-c/GRPCClient/GRPCCall+ChannelArg.h | 34 +--------------------- src/objective-c/GRPCClient/GRPCCall+ChannelArg.m | 5 ++-- .../GRPCClient/GRPCCall+ChannelCredentials.h | 10 +------ src/objective-c/GRPCClient/GRPCCall+Cronet.h | 13 +-------- src/objective-c/GRPCClient/GRPCCall+OAuth2.h | 29 +++--------------- src/objective-c/GRPCClient/GRPCCall+Tests.h | 25 ++-------------- src/objective-c/GRPCClient/GRPCCall+Tests.m | 4 ++- 7 files changed, 15 insertions(+), 105 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h index 803f19dedf..2ddd53a5c6 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h @@ -19,52 +19,20 @@ #include -typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) { - GRPCCompressNone, - GRPCCompressDeflate, - GRPCCompressGzip, -}; - -/** - * Methods to configure GRPC channel options. - */ +// Deprecated interface. Please use GRPCCallOptions instead. @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:(nonnull NSString *)userAgentPrefix forHost:(nonnull NSString *)host; - -/** The default response size limit is 4MB. Set this to override that default. */ + (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host; - + (void)closeOpenConnections DEPRECATED_MSG_ATTRIBUTE( "The API for this feature is experimental, " "and might be removed or modified at any " "time."); - + (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm forhost:(nonnull NSString *)host; - -/** Enable keepalive and configure keepalive parameters. A user should call this function once to - * enable keepalive for a particular host. gRPC client sends a ping after every \a interval ms to - * check if the transport is still alive. After waiting for \a timeout ms, if the client does not - * receive the ping ack, it closes the transport; all pending calls to this host will fail with - * error GRPC_STATUS_INTERNAL with error information "keepalive watchdog timeout". */ + (void)setKeepaliveWithInterval:(int)interval timeout:(int)timeout forHost:(nonnull NSString *)host; - -/** Enable/Disable automatic retry of gRPC calls on the channel. If automatic retry is enabled, the - * retry is controlled by server's service config. If automatic retry is disabled, failed calls are - * immediately returned to the application layer. */ + (void)enableRetry:(BOOL)enabled forHost:(nonnull NSString *)host; - -/** Set channel connection timeout and backoff parameters. All parameters are positive integers in - * milliseconds. Set a parameter to 0 to make gRPC use default value for that parameter. - * - * Refer to gRPC's doc at https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md for the - * details of each parameter. */ + (void)setMinConnectTimeout:(unsigned int)timeout initialBackoff:(unsigned int)initialBackoff maxBackoff:(unsigned int)maxBackoff diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m index 0e631fb3ad..d01d0c0d4f 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m @@ -18,6 +18,7 @@ #import "GRPCCall+ChannelArg.h" +#import "private/GRPCChannel.h" #import "private/GRPCHost.h" #import @@ -31,11 +32,11 @@ + (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host { GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; - hostConfig.responseSizeLimitOverride = @(limit); + hostConfig.responseSizeLimitOverride = limit; } + (void)closeOpenConnections { - [GRPCHost flushChannelCache]; + [GRPCChannel closeOpenConnections]; } + (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm forhost:(nonnull NSString *)host { diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h index d7d15c4ee3..7d6f79b765 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h @@ -18,20 +18,12 @@ #import "GRPCCall.h" -/** Helpers for setting TLS Trusted Roots, Client Certificates, and Private Key */ +// Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (ChannelCredentials) -/** - * Use the provided @c pemRootCert as the set of trusted root Certificate Authorities for @c host. - */ + (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert forHost:(nonnull NSString *)host error:(NSError *_Nullable *_Nullable)errorPtr; -/** - * Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate - * Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be - * used. - */ + (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts withPrivateKey:(nullable NSString *)pemPrivateKey withCertChain:(nullable NSString *)pemCertChain diff --git a/src/objective-c/GRPCClient/GRPCCall+Cronet.h b/src/objective-c/GRPCClient/GRPCCall+Cronet.h index 2a5f6e9cf0..3059c6f186 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Cronet.h +++ b/src/objective-c/GRPCClient/GRPCCall+Cronet.h @@ -20,22 +20,11 @@ #import "GRPCCall.h" -/** - * Methods for using cronet transport. - */ +// Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (Cronet) -/** - * This method should be called before issuing the first RPC. It should be - * called only once. Create an instance of Cronet engine in your app elsewhere - * and pass the instance pointer in the stream_engine parameter. Once set, - * all subsequent RPCs will use Cronet transport. The method is not thread - * safe. - */ + (void)useCronetWithEngine:(stream_engine*)engine; - + (stream_engine*)cronetEngine; - + (BOOL)isUsingCronet; @end diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h index adb1042aa0..3054bfc5a7 100644 --- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h @@ -18,34 +18,13 @@ #import "GRPCCall.h" -/** - * The protocol of an OAuth2 token object from which GRPCCall can acquire a token. - */ -@protocol GRPCAuthorizationProtocol -- (void)getTokenWithHandler:(void (^)(NSString *token))hander; -@end +#import "GRPCCallOptions.h" -/** Helpers for setting and reading headers compatible with OAuth2. */ +// Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (OAuth2) -/** - * Setting this property is equivalent to setting "Bearer " as the value of the - * request header with key "authorization" (the authorization header). Setting it to nil removes the - * authorization header from the request. - * The value obtained by getting the property is the OAuth2 bearer token if the authorization header - * of the request has the form "Bearer ", or nil otherwise. - */ -@property(atomic, copy) NSString *oauth2AccessToken; - -/** Returns the value (if any) of the "www-authenticate" response header (the challenge header). */ -@property(atomic, readonly) NSString *oauth2ChallengeHeader; - -/** - * The authorization token object to be used when starting the call. If the value is set to nil, no - * oauth authentication will be used. - * - * If tokenProvider exists, it takes precedence over the token set by oauth2AccessToken. - */ +@property(atomic, copy) NSString* oauth2AccessToken; +@property(atomic, readonly) NSString* oauth2ChallengeHeader; @property(atomic, strong) id tokenProvider; @end diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.h b/src/objective-c/GRPCClient/GRPCCall+Tests.h index 5d35182ae5..edaa5ed582 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.h +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.h @@ -18,34 +18,13 @@ #import "GRPCCall.h" -/** - * Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be - * used in releases, but are sometimes needed for testing. - */ +// Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (Tests) -/** - * Establish all SSL connections to the provided host using the passed SSL target name and the root - * certificates found in the file at |certsPath|. - * - * Must be called before any gRPC call to that host is made. It's illegal to pass the same host to - * more than one invocation of the methods of this category. - */ + (void)useTestCertsPath:(NSString *)certsPath testName:(NSString *)testName forHost:(NSString *)host; - -/** - * Establish all connections to the provided host using cleartext instead of SSL. - * - * Must be called before any gRPC call to that host is made. It's illegal to pass the same host to - * more than one invocation of the methods of this category. - */ + (void)useInsecureConnectionsForHost:(NSString *)host; - -/** - * Resets all host configurations to their default values, and flushes all connections from the - * cache. - */ + (void)resetHostSettings; + @end diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.m index 0db3ad6b39..ac3b6a658f 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.m +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.m @@ -20,6 +20,8 @@ #import "private/GRPCHost.h" +#import "GRPCCallOptions.h" + @implementation GRPCCall (Tests) + (void)useTestCertsPath:(NSString *)certsPath @@ -42,7 +44,7 @@ + (void)useInsecureConnectionsForHost:(NSString *)host { GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; - hostConfig.secure = NO; + hostConfig.transportType = GRPCTransportTypeInsecure; } + (void)resetHostSettings { -- cgit v1.2.3 From 309ba191525a96c5314e5762ecaa2fffbc9eccbb Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 8 Oct 2018 15:52:27 -0700 Subject: Channel pool --- .../GRPCClient/private/ChannelArgsUtil.h | 25 ++ .../GRPCClient/private/ChannelArgsUtil.m | 95 +++++ src/objective-c/GRPCClient/private/GRPCChannel.h | 43 +-- src/objective-c/GRPCClient/private/GRPCChannel.m | 242 ++++--------- .../GRPCClient/private/GRPCChannelFactory.h | 32 ++ .../GRPCClient/private/GRPCChannelPool.h | 69 ++++ .../GRPCClient/private/GRPCChannelPool.m | 387 +++++++++++++++++++++ .../GRPCClient/private/GRPCCronetChannelFactory.h | 36 ++ .../GRPCClient/private/GRPCCronetChannelFactory.m | 94 +++++ src/objective-c/GRPCClient/private/GRPCHost.h | 31 +- src/objective-c/GRPCClient/private/GRPCHost.m | 261 +++----------- .../private/GRPCInsecureChannelFactory.h | 35 ++ .../private/GRPCInsecureChannelFactory.m | 48 +++ .../GRPCClient/private/GRPCSecureChannelFactory.h | 38 ++ .../GRPCClient/private/GRPCSecureChannelFactory.m | 129 +++++++ .../GRPCClient/private/GRPCWrappedCall.h | 3 +- .../GRPCClient/private/GRPCWrappedCall.m | 18 +- 17 files changed, 1138 insertions(+), 448 deletions(-) create mode 100644 src/objective-c/GRPCClient/private/ChannelArgsUtil.h create mode 100644 src/objective-c/GRPCClient/private/ChannelArgsUtil.m create mode 100644 src/objective-c/GRPCClient/private/GRPCChannelFactory.h create mode 100644 src/objective-c/GRPCClient/private/GRPCChannelPool.h create mode 100644 src/objective-c/GRPCClient/private/GRPCChannelPool.m create mode 100644 src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h create mode 100644 src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m create mode 100644 src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h create mode 100644 src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m create mode 100644 src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h create mode 100644 src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.h b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h new file mode 100644 index 0000000000..d9d6933c6b --- /dev/null +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h @@ -0,0 +1,25 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#include + +void FreeChannelArgs(grpc_channel_args* channel_args); + +grpc_channel_args* BuildChannelArgs(NSDictionary* dictionary); diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m new file mode 100644 index 0000000000..8ebf3a2659 --- /dev/null +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -0,0 +1,95 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "ChannelArgsUtil.h" + +#include +#include + +static void *copy_pointer_arg(void *p) { + // Add ref count to the object when making copy + id obj = (__bridge id)p; + return (__bridge_retained void *)obj; +} + +static void destroy_pointer_arg(void *p) { + // Decrease ref count to the object when destroying + CFRelease((CFTreeRef)p); +} + +static int cmp_pointer_arg(void *p, void *q) { return p == q; } + +static const grpc_arg_pointer_vtable objc_arg_vtable = {copy_pointer_arg, destroy_pointer_arg, + cmp_pointer_arg}; + +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->args); + 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; + } + + 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 if (value != nil) { + arg->type = GRPC_ARG_POINTER; + arg->value.pointer.p = (__bridge_retained void *)value; + arg->value.pointer.vtable = &objc_arg_vtable; + } else { + [NSException raise:NSInvalidArgumentException + format:@"Invalid value type: %@", [value class]]; + } + } + + return channelArgs; +} diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 6499d4398c..7d5039a8a2 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -21,6 +21,8 @@ #include @class GRPCCompletionQueue; +@class GRPCCallOptions; +@class GRPCChannelConfiguration; struct grpc_channel_credentials; /** @@ -28,41 +30,30 @@ struct grpc_channel_credentials; */ @interface GRPCChannel : NSObject -@property(nonatomic, readonly, nonnull) struct grpc_channel *unmanagedChannel; - - (nullable instancetype)init NS_UNAVAILABLE; /** - * 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. + * Returns a channel connecting to \a host with options as \a callOptions. The channel may be new + * or a cached channel that is already connected. */ -+ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host; ++ (nullable instancetype)channelWithHost:(nonnull NSString *)host + callOptions:(nullable GRPCCallOptions *)callOptions; /** - * Creates a secure channel to the specified @c host using Cronet as a transport mechanism. - */ -#ifdef GRPC_COMPILE_WITH_CRONET -+ (nullable GRPCChannel *)secureCronetChannelWithHost:(nonnull NSString *)host - channelArgs:(nonnull NSDictionary *)channelArgs; -#endif -/** - * 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. + * Get a grpc core call object from this channel. */ -+ (nonnull GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host - credentials: - (nonnull struct grpc_channel_credentials *)credentials - channelArgs:(nullable NSDictionary *)channelArgs; +- (nullable grpc_call *)unmanagedCallWithPath:(nonnull NSString *)path + completionQueue:(nonnull GRPCCompletionQueue *)queue + callOptions:(nonnull GRPCCallOptions *)callOptions; + +- (void)unmanagedCallUnref; /** - * Creates an insecure channel to the specified @c host using the specified @c channelArgs. + * Create a channel object with the signature \a config. This function is used for testing only. Use + * channelWithHost:callOptions: in production. */ -+ (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host - channelArgs:(nullable NSDictionary *)channelArgs; ++ (nullable instancetype)createChannelWithConfiguration:(nonnull GRPCChannelConfiguration *)config; -- (nullable grpc_call *)unmanagedCallWithPath:(nonnull NSString *)path - serverName:(nonnull NSString *)serverName - timeout:(NSTimeInterval)timeout - completionQueue:(nonnull GRPCCompletionQueue *)queue; +// TODO (mxyan): deprecate with GRPCCall:closeOpenConnections ++ (void)closeOpenConnections; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index b1f6ea270e..cf44b96e22 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -18,206 +18,106 @@ #import "GRPCChannel.h" -#include -#ifdef GRPC_COMPILE_WITH_CRONET -#include -#endif -#include #include -#include -#ifdef GRPC_COMPILE_WITH_CRONET -#import -#import -#endif +#import "ChannelArgsUtil.h" +#import "GRPCChannelFactory.h" +#import "GRPCChannelPool.h" #import "GRPCCompletionQueue.h" +#import "GRPCConnectivityMonitor.h" +#import "GRPCCronetChannelFactory.h" +#import "GRPCInsecureChannelFactory.h" +#import "GRPCSecureChannelFactory.h" +#import "version.h" -static void *copy_pointer_arg(void *p) { - // Add ref count to the object when making copy - id obj = (__bridge id)p; - return (__bridge_retained void *)obj; -} - -static void destroy_pointer_arg(void *p) { - // Decrease ref count to the object when destroying - CFRelease((CFTreeRef)p); -} - -static int cmp_pointer_arg(void *p, void *q) { return p == q; } - -static const grpc_arg_pointer_vtable objc_arg_vtable = {copy_pointer_arg, destroy_pointer_arg, - cmp_pointer_arg}; - -static 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->args); - 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. - */ -static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) { - if (!dictionary) { - return 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 if (value != nil) { - arg->type = GRPC_ARG_POINTER; - arg->value.pointer.p = (__bridge_retained void *)value; - arg->value.pointer.vtable = &objc_arg_vtable; - } else { - [NSException raise:NSInvalidArgumentException - format:@"Invalid value type: %@", [value class]]; - } - } - - return channelArgs; -} +#import +#import @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; + GRPCChannelConfiguration *_configuration; + grpc_channel *_unmanagedChannel; } -#ifdef GRPC_COMPILE_WITH_CRONET -- (instancetype)initWithHost:(NSString *)host - cronetEngine:(stream_engine *)cronetEngine - channelArgs:(NSDictionary *)channelArgs { - if (!host) { - [NSException raise:NSInvalidArgumentException format:@"host argument missing"]; +- (grpc_call *)unmanagedCallWithPath:(NSString *)path + completionQueue:(nonnull GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions { + NSString *serverAuthority = callOptions.serverAuthority; + NSTimeInterval timeout = callOptions.timeout; + GPR_ASSERT(timeout >= 0); + grpc_slice host_slice = grpc_empty_slice(); + if (serverAuthority) { + host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); } - - if (self = [super init]) { - _channelArgs = BuildChannelArgs(channelArgs); - _host = [host copy]; - _unmanagedChannel = - grpc_cronet_secure_channel_create(cronetEngine, _host.UTF8String, _channelArgs, NULL); + grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); + gpr_timespec deadline_ms = + timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + grpc_call *call = grpc_channel_create_call( + _unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, + serverAuthority ? &host_slice : NULL, deadline_ms, NULL); + if (serverAuthority) { + grpc_slice_unref(host_slice); } - - return self; + grpc_slice_unref(path_slice); + return call; } -#endif - -- (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; - } +- (void)unmanagedCallUnref { + [kChannelPool unrefChannelWithConfiguration:_configuration]; +} - 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); - } +- (nullable instancetype)initWithUnmanagedChannel:(nullable grpc_channel *)unmanagedChannel + configuration:(GRPCChannelConfiguration *)configuration { + if ((self = [super init])) { + _unmanagedChannel = unmanagedChannel; + _configuration = configuration; } - return self; } - (void)dealloc { - // 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); } -#ifdef GRPC_COMPILE_WITH_CRONET -+ (GRPCChannel *)secureCronetChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *)channelArgs { - stream_engine *engine = [GRPCCall cronetEngine]; - if (!engine) { - [NSException raise:NSInvalidArgumentException format:@"cronet_engine is NULL. Set it first."]; ++ (nullable instancetype)createChannelWithConfiguration:(GRPCChannelConfiguration *)config { + NSString *host = config.host; + if (host == nil || [host length] == 0) { return nil; } - return [[GRPCChannel alloc] initWithHost:host cronetEngine:engine channelArgs:channelArgs]; -} -#endif -+ (GRPCChannel *)secureChannelWithHost:(NSString *)host { - return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL channelArgs:NULL]; + NSMutableDictionary *channelArgs = config.channelArgs; + [channelArgs addEntriesFromDictionary:config.callOptions.additionalChannelArgs]; + id factory = config.channelFactory; + grpc_channel *unmanaged_channel = [factory createChannelWithHost:host channelArgs:channelArgs]; + return [[GRPCChannel alloc] initWithUnmanagedChannel:unmanaged_channel configuration:config]; } -+ (GRPCChannel *)secureChannelWithHost:(NSString *)host - credentials:(struct grpc_channel_credentials *)credentials - channelArgs:(NSDictionary *)channelArgs { - return [[GRPCChannel alloc] initWithHost:host - secure:YES - credentials:credentials - channelArgs:channelArgs]; -} +static dispatch_once_t initChannelPool; +static GRPCChannelPool *kChannelPool; -+ (GRPCChannel *)insecureChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)channelArgs { - return [[GRPCChannel alloc] initWithHost:host secure:NO credentials:NULL channelArgs:channelArgs]; -} ++ (nullable instancetype)channelWithHost:(NSString *)host + callOptions:(GRPCCallOptions *)callOptions { + dispatch_once(&initChannelPool, ^{ + kChannelPool = [[GRPCChannelPool alloc] init]; + }); -- (grpc_call *)unmanagedCallWithPath:(NSString *)path - serverName:(NSString *)serverName - timeout:(NSTimeInterval)timeout - completionQueue:(GRPCCompletionQueue *)queue { - GPR_ASSERT(timeout >= 0); - if (timeout < 0) { - timeout = 0; + NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:host]]; + if (hostURL.host && !hostURL.port) { + host = [hostURL.host stringByAppendingString:@":443"]; } - grpc_slice host_slice = grpc_empty_slice(); - if (serverName) { - host_slice = grpc_slice_from_copied_string(serverName.UTF8String); - } - grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); - gpr_timespec deadline_ms = - timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); - grpc_call *call = grpc_channel_create_call(_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, - queue.unmanagedQueue, path_slice, - serverName ? &host_slice : NULL, deadline_ms, NULL); - if (serverName) { - grpc_slice_unref(host_slice); - } - grpc_slice_unref(path_slice); - return call; + + GRPCChannelConfiguration *channelConfig = + [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; + return [kChannelPool channelWithConfiguration:channelConfig + createChannel:^{ + return + [GRPCChannel createChannelWithConfiguration:channelConfig]; + }]; +} + ++ (void)closeOpenConnections { + [kChannelPool clear]; } @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h new file mode 100644 index 0000000000..e44f8260df --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h @@ -0,0 +1,32 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#include + +NS_ASSUME_NONNULL_BEGIN + +@protocol GRPCChannelFactory + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableDictionary *)args; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h new file mode 100644 index 0000000000..1145039549 --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -0,0 +1,69 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * Signature for the channel. If two channel's signatures are the same, they share the same + * underlying \a GRPCChannel object. + */ + +#import + +#import "GRPCChannelFactory.h" + +NS_ASSUME_NONNULL_BEGIN + +@class GRPCChannel; + +@interface GRPCChannelConfiguration : NSObject + +@property(atomic, strong, readwrite) NSString *host; +@property(atomic, strong, readwrite) GRPCCallOptions *callOptions; + +@property(readonly) id channelFactory; +@property(readonly) NSMutableDictionary *channelArgs; + +- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; + +@end + +/** + * Manage the pool of connected channels. When a channel is no longer referenced by any call, + * destroy the channel after a certain period of time elapsed. + */ +@interface GRPCChannelPool : NSObject + +- (instancetype)init; + +- (instancetype)initWithChannelDestroyDelay:(NSTimeInterval)channelDestroyDelay; + +/** + * Return a channel with a particular configuration. If the channel does not exist, execute \a + * createChannel then add it in the pool. If the channel exists, increase its reference count. + */ +- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration + createChannel:(GRPCChannel * (^)(void))createChannel; + +/** Decrease a channel's refcount. */ +- (void)unrefChannelWithConfiguration:configuration; + +/** Clear all channels in the pool. */ +- (void)clear; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m new file mode 100644 index 0000000000..b5f0949ef7 --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -0,0 +1,387 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import "GRPCChannelFactory.h" +#import "GRPCChannelPool.h" +#import "GRPCConnectivityMonitor.h" +#import "GRPCCronetChannelFactory.h" +#import "GRPCInsecureChannelFactory.h" +#import "GRPCSecureChannelFactory.h" +#import "version.h" + +#import +#include + +extern const char *kCFStreamVarName; + +// When all calls of a channel are destroyed, destroy the channel after this much seconds. +const NSTimeInterval kChannelDestroyDelay = 30; + +@implementation GRPCChannelConfiguration + +- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { + if ((self = [super init])) { + _host = host; + _callOptions = callOptions; + } + return self; +} + +- (id)channelFactory { + NSError *error; + id factory; + GRPCTransportType type = _callOptions.transportType; + switch (type) { + case GRPCTransportTypeDefault: + // TODO (mxyan): Remove when the API is deprecated +#ifdef GRPC_COMPILE_WITH_CRONET + if (![GRPCCall isUsingCronet]) { +#endif + factory = [GRPCSecureChannelFactory factoryWithPEMRootCerts:_callOptions.pemRootCert + privateKey:_callOptions.pemPrivateKey + certChain:_callOptions.pemCertChain + error:&error]; + if (error) { + NSLog(@"Error creating secure channel factory: %@", error); + return nil; + } + return factory; +#ifdef GRPC_COMPILE_WITH_CRONET + } +#endif + // fallthrough + case GRPCTransportTypeCronet: + return [GRPCCronetChannelFactory sharedInstance]; + case GRPCTransportTypeInsecure: + return [GRPCInsecureChannelFactory sharedInstance]; + default: + GPR_UNREACHABLE_CODE(return nil); + } +} + +- (NSMutableDictionary *)channelArgs { + NSMutableDictionary *args = [NSMutableDictionary new]; + + NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING; + NSString *userAgentPrefix = _callOptions.userAgentPrefix; + if (userAgentPrefix) { + args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = + [_callOptions.userAgentPrefix stringByAppendingFormat:@" %@", userAgent]; + } else { + args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent; + } + + NSString *hostNameOverride = _callOptions.hostNameOverride; + if (hostNameOverride) { + args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = hostNameOverride; + } + + if (_callOptions.responseSizeLimit) { + args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = + [NSNumber numberWithUnsignedInteger:_callOptions.responseSizeLimit]; + } + + if (_callOptions.compressAlgorithm != GRPC_COMPRESS_NONE) { + args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = + [NSNumber numberWithInt:_callOptions.compressAlgorithm]; + } + + if (_callOptions.keepaliveInterval != 0) { + args[@GRPC_ARG_KEEPALIVE_TIME_MS] = + [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.keepaliveInterval * 1000)]; + args[@GRPC_ARG_KEEPALIVE_TIMEOUT_MS] = + [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.keepaliveTimeout * 1000)]; + } + + if (_callOptions.enableRetry == NO) { + args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:_callOptions.enableRetry]; + } + + if (_callOptions.connectMinTimeout > 0) { + args[@GRPC_ARG_MIN_RECONNECT_BACKOFF_MS] = + [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.connectMinTimeout * 1000)]; + } + if (_callOptions.connectInitialBackoff > 0) { + args[@GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS] = [NSNumber + numberWithUnsignedInteger:(unsigned int)(_callOptions.connectInitialBackoff * 1000)]; + } + if (_callOptions.connectMaxBackoff > 0) { + args[@GRPC_ARG_MAX_RECONNECT_BACKOFF_MS] = + [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.connectMaxBackoff * 1000)]; + } + + if (_callOptions.logContext != nil) { + args[@GRPC_ARG_MOBILE_LOG_CONTEXT] = _callOptions.logContext; + } + + if (_callOptions.channelPoolDomain != nil) { + args[@GRPC_ARG_CHANNEL_POOL_DOMAIN] = _callOptions.channelPoolDomain; + } + + [args addEntriesFromDictionary:_callOptions.additionalChannelArgs]; + + return args; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + GRPCChannelConfiguration *newConfig = [[GRPCChannelConfiguration alloc] init]; + newConfig.host = _host; + newConfig.callOptions = _callOptions; + + return newConfig; +} + +- (BOOL)isEqual:(id)object { + NSAssert([object isKindOfClass:[GRPCChannelConfiguration class]], @"Illegal :isEqual"); + GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; + if (!(obj.host == _host || [obj.host isEqualToString:_host])) return NO; + if (!(obj.callOptions.userAgentPrefix == _callOptions.userAgentPrefix || + [obj.callOptions.userAgentPrefix isEqualToString:_callOptions.userAgentPrefix])) + return NO; + if (!(obj.callOptions.responseSizeLimit == _callOptions.responseSizeLimit)) return NO; + if (!(obj.callOptions.compressAlgorithm == _callOptions.compressAlgorithm)) return NO; + if (!(obj.callOptions.enableRetry == _callOptions.enableRetry)) return NO; + if (!(obj.callOptions.keepaliveInterval == _callOptions.keepaliveInterval)) return NO; + if (!(obj.callOptions.keepaliveTimeout == _callOptions.keepaliveTimeout)) return NO; + if (!(obj.callOptions.connectMinTimeout == _callOptions.connectMinTimeout)) return NO; + if (!(obj.callOptions.connectInitialBackoff == _callOptions.connectInitialBackoff)) return NO; + if (!(obj.callOptions.connectMaxBackoff == _callOptions.connectMaxBackoff)) return NO; + if (!(obj.callOptions.additionalChannelArgs == _callOptions.additionalChannelArgs || + [obj.callOptions.additionalChannelArgs + isEqualToDictionary:_callOptions.additionalChannelArgs])) + return NO; + if (!(obj.callOptions.pemRootCert == _callOptions.pemRootCert || + [obj.callOptions.pemRootCert isEqualToString:_callOptions.pemRootCert])) + return NO; + if (!(obj.callOptions.pemPrivateKey == _callOptions.pemPrivateKey || + [obj.callOptions.pemPrivateKey isEqualToString:_callOptions.pemPrivateKey])) + return NO; + if (!(obj.callOptions.pemCertChain == _callOptions.pemCertChain || + [obj.callOptions.pemCertChain isEqualToString:_callOptions.pemCertChain])) + return NO; + if (!(obj.callOptions.hostNameOverride == _callOptions.hostNameOverride || + [obj.callOptions.hostNameOverride isEqualToString:_callOptions.hostNameOverride])) + return NO; + if (!(obj.callOptions.transportType == _callOptions.transportType)) return NO; + if (!(obj.callOptions.logContext == _callOptions.logContext || + [obj.callOptions.logContext isEqual:_callOptions.logContext])) + return NO; + if (!(obj.callOptions.channelPoolDomain == _callOptions.channelPoolDomain || + [obj.callOptions.channelPoolDomain isEqualToString:_callOptions.channelPoolDomain])) + return NO; + if (!(obj.callOptions.channelId == _callOptions.channelId)) return NO; + + return YES; +} + +- (NSUInteger)hash { + NSUInteger result = 0; + result ^= _host.hash; + result ^= _callOptions.userAgentPrefix.hash; + result ^= _callOptions.responseSizeLimit; + result ^= _callOptions.compressAlgorithm; + result ^= _callOptions.enableRetry; + result ^= (unsigned int)(_callOptions.keepaliveInterval * 1000); + result ^= (unsigned int)(_callOptions.keepaliveTimeout * 1000); + result ^= (unsigned int)(_callOptions.connectMinTimeout * 1000); + result ^= (unsigned int)(_callOptions.connectInitialBackoff * 1000); + result ^= (unsigned int)(_callOptions.connectMaxBackoff * 1000); + result ^= _callOptions.additionalChannelArgs.hash; + result ^= _callOptions.pemRootCert.hash; + result ^= _callOptions.pemPrivateKey.hash; + result ^= _callOptions.pemCertChain.hash; + result ^= _callOptions.hostNameOverride.hash; + result ^= _callOptions.transportType; + result ^= [_callOptions.logContext hash]; + result ^= _callOptions.channelPoolDomain.hash; + result ^= _callOptions.channelId; + + return result; +} + +@end + +/** + * Time the channel destroy when the channel's calls are unreffed. If there's new call, reset the + * timer. + */ +@interface GRPCChannelCallRef : NSObject + +- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)configuration + destroyDelay:(NSTimeInterval)destroyDelay + dispatchQueue:(dispatch_queue_t)dispatchQueue + destroyChannel:(void (^)())destroyChannel; + +/** Add call ref count to the channel and maybe reset the timer. */ +- (void)refChannel; + +/** Reduce call ref count to the channel and maybe set the timer. */ +- (void)unrefChannel; + +@end + +@implementation GRPCChannelCallRef { + GRPCChannelConfiguration *_configuration; + NSTimeInterval _destroyDelay; + // We use dispatch queue for this purpose since timer invalidation must happen on the same + // thread which issued the timer. + dispatch_queue_t _dispatchQueue; + void (^_destroyChannel)(); + + NSUInteger _refCount; + NSTimer *_timer; +} + +- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)configuration + destroyDelay:(NSTimeInterval)destroyDelay + dispatchQueue:(dispatch_queue_t)dispatchQueue + destroyChannel:(void (^)())destroyChannel { + if ((self = [super init])) { + _configuration = configuration; + _destroyDelay = destroyDelay; + _dispatchQueue = dispatchQueue; + _destroyChannel = destroyChannel; + + _refCount = 0; + _timer = nil; + } + return self; +} + +// This function is protected by channel pool dispatch queue. +- (void)refChannel { + _refCount++; + if (_timer) { + [_timer invalidate]; + } + _timer = nil; +} + +// This function is protected by channel spool dispatch queue. +- (void)unrefChannel { + self->_refCount--; + if (self->_refCount == 0) { + if (self->_timer) { + [self->_timer invalidate]; + } + self->_timer = [NSTimer scheduledTimerWithTimeInterval:self->_destroyDelay + target:self + selector:@selector(timerFire:) + userInfo:nil + repeats:NO]; + } +} + +- (void)timerFire:(NSTimer *)timer { + dispatch_sync(_dispatchQueue, ^{ + if (self->_timer == nil || self->_timer != timer) { + return; + } + self->_timer = nil; + self->_destroyChannel(self->_configuration); + }); +} + +@end + +#pragma mark GRPCChannelPool + +@implementation GRPCChannelPool { + NSTimeInterval _channelDestroyDelay; + NSMutableDictionary *_channelPool; + NSMutableDictionary *_callRefs; + // Dedicated queue for timer + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)init { + return [self initWithChannelDestroyDelay:kChannelDestroyDelay]; +} + +- (instancetype)initWithChannelDestroyDelay:(NSTimeInterval)channelDestroyDelay { + if ((self = [super init])) { + _channelDestroyDelay = channelDestroyDelay; + _channelPool = [NSMutableDictionary dictionary]; + _callRefs = [NSMutableDictionary dictionary]; + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + + // Connectivity monitor is not required for CFStream + char *enableCFStream = getenv(kCFStreamVarName); + if (enableCFStream == nil || enableCFStream[0] != '1') { + [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)]; + } + } + return self; +} + +- (void)dealloc { + // Connectivity monitor is not required for CFStream + char *enableCFStream = getenv(kCFStreamVarName); + if (enableCFStream == nil || enableCFStream[0] != '1') { + [GRPCConnectivityMonitor unregisterObserver:self]; + } +} + +- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration + createChannel:(GRPCChannel * (^)(void))createChannel { + __block GRPCChannel *channel; + dispatch_sync(_dispatchQueue, ^{ + if ([self->_channelPool objectForKey:configuration]) { + [self->_callRefs[configuration] refChannel]; + channel = self->_channelPool[configuration]; + } else { + channel = createChannel(); + self->_channelPool[configuration] = channel; + + GRPCChannelCallRef *callRef = [[GRPCChannelCallRef alloc] + initWithChannelConfiguration:configuration + destroyDelay:self->_channelDestroyDelay + dispatchQueue:self->_dispatchQueue + destroyChannel:^(GRPCChannelConfiguration *configuration) { + [self->_channelPool removeObjectForKey:configuration]; + [self->_callRefs removeObjectForKey:configuration]; + }]; + [callRef refChannel]; + self->_callRefs[configuration] = callRef; + } + }); + return channel; +} + +- (void)unrefChannelWithConfiguration:configuration { + dispatch_sync(_dispatchQueue, ^{ + if ([self->_channelPool objectForKey:configuration]) { + [self->_callRefs[configuration] unrefChannel]; + } + }); +} + +- (void)clear { + dispatch_sync(_dispatchQueue, ^{ + self->_channelPool = [NSMutableDictionary dictionary]; + self->_callRefs = [NSMutableDictionary dictionary]; + }); +} + +- (void)connectivityChange:(NSNotification *)note { + [self clear]; +} + +@end diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h new file mode 100644 index 0000000000..97e1ae920a --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h @@ -0,0 +1,36 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#import "GRPCChannelFactory.h" + +@class GRPCChannel; +typedef struct stream_engine stream_engine; + +NS_ASSUME_NONNULL_BEGIN + +@interface GRPCCronetChannelFactory : NSObject + ++ (nullable instancetype)sharedInstance; + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableDictionary *)args; + +- (nullable instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m new file mode 100644 index 0000000000..5c0fe16d39 --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -0,0 +1,94 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GRPCCronetChannelFactory.h" + +#import "ChannelArgsUtil.h" +#import "GRPCChannel.h" + +#ifdef GRPC_COMPILE_WITH_CRONET + +#import +#include + +NS_ASSUME_NONNULL_BEGIN + +@implementation GRPCCronetChannelFactory { + stream_engine *_cronetEngine; +} + ++ (nullable instancetype)sharedInstance { + static GRPCCronetChannelFactory *instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] initWithEngine:[Cronet getGlobalEngine]]; + }); + return instance; +} + +- (nullable instancetype)initWithEngine:(stream_engine *)engine { + if (!engine) { + [NSException raise:NSInvalidArgumentException format:@"Cronet engine is NULL. Set it first."]; + return nil; + } + if ((self = [super init])) { + _cronetEngine = engine; + } + return self; +} + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableDictionary *)args { + // Remove client authority filter since that is not supported + args[@GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER] = [NSNumber numberWithInt:1]; + + grpc_channel_args *channelArgs = BuildChannelArgs(args); + grpc_channel *unmanagedChannel = + grpc_cronet_secure_channel_create(_cronetEngine, host.UTF8String, channelArgs, NULL); + FreeChannelArgs(channelArgs); + return unmanagedChannel; +} + +@end + +NS_ASSUME_NONNULL_END + +#else + +NS_ASSUME_NONNULL_BEGIN + +@implementation GRPCCronetChannelFactory + ++ (nullable instancetype)sharedInstance { + [NSException raise:NSInvalidArgumentException + format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; + return nil; +} + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableArray *)args { + [NSException raise:NSInvalidArgumentException + format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; + return nil; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h index 291b07df37..32d3585351 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.h +++ b/src/objective-c/GRPCClient/private/GRPCHost.h @@ -20,6 +20,10 @@ #import +#import "GRPCChannelFactory.h" + +#import + NS_ASSUME_NONNULL_BEGIN @class GRPCCompletionQueue; @@ -28,12 +32,10 @@ struct grpc_channel_credentials; @interface GRPCHost : NSObject -+ (void)flushChannelCache; + (void)resetAllHostSettings; @property(nonatomic, readonly) NSString *address; @property(nonatomic, copy, nullable) NSString *userAgentPrefix; -@property(nonatomic, nullable) struct grpc_channel_credentials *channelCreds; @property(nonatomic) grpc_compression_algorithm compressAlgorithm; @property(nonatomic) int keepaliveInterval; @property(nonatomic) int keepaliveTimeout; @@ -44,14 +46,14 @@ struct grpc_channel_credentials; @property(nonatomic) unsigned int initialConnectBackoff; @property(nonatomic) unsigned int maxConnectBackoff; -/** The following properties should only be modified for testing: */ +@property(nonatomic) id channelFactory; -@property(nonatomic, getter=isSecure) BOOL secure; +/** The following properties should only be modified for testing: */ @property(nonatomic, copy, nullable) NSString *hostNameOverride; /** The default response size limit is 4MB. Set this to override that default. */ -@property(nonatomic, strong, nullable) NSNumber *responseSizeLimitOverride; +@property(nonatomic) NSUInteger responseSizeLimitOverride; - (nullable instancetype)init NS_UNAVAILABLE; /** Host objects initialized with the same address are the same. */ @@ -62,19 +64,12 @@ struct grpc_channel_credentials; withCertChain:(nullable NSString *)pemCertChain error:(NSError **)errorPtr; -/** Create a grpc_call object to the provided path on this host. */ -- (nullable struct grpc_call *)unmanagedCallWithPath:(NSString *)path - serverName:(NSString *)serverName - timeout:(NSTimeInterval)timeout - completionQueue:(GRPCCompletionQueue *)queue; - -// TODO: There's a race when a new RPC is coming through just as an existing one is getting -// notified that there's no connectivity. If connectivity comes back at that moment, the new RPC -// will have its channel destroyed by the other RPC, and will never get notified of a problem, so -// it'll hang (the C layer logs a timeout, with exponential back off). One solution could be to pass -// the GRPCChannel to the GRPCCall, renaming this as "disconnectChannel:channel", which would only -// act on that specific channel. -- (void)disconnect; +@property(atomic, readwrite) GRPCTransportType transportType; + +@property(readonly) GRPCMutableCallOptions *callOptions; + ++ (BOOL)isHostConfigured:(NSString *)address; + @end NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 862909f238..0e3fa610f9 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -18,46 +18,35 @@ #import "GRPCHost.h" +#import #import + #include #include -#ifdef GRPC_COMPILE_WITH_CRONET -#import -#import -#endif -#import "GRPCChannel.h" +#import +#import "GRPCChannelFactory.h" #import "GRPCCompletionQueue.h" #import "GRPCConnectivityMonitor.h" +#import "GRPCCronetChannelFactory.h" +#import "GRPCSecureChannelFactory.h" #import "NSDictionary+GRPC.h" #import "version.h" NS_ASSUME_NONNULL_BEGIN -extern const char *kCFStreamVarName; - static NSMutableDictionary *kHostCache; @implementation GRPCHost { - // TODO(mlumish): Investigate whether caching channels with strong links is a good idea. - GRPCChannel *_channel; + NSString *_pemRootCerts; + NSString *_pemPrivateKey; + NSString *_pemCertChain; } + (nullable instancetype)hostWithAddress:(NSString *)address { return [[self alloc] initWithAddress:address]; } -- (void)dealloc { - if (_channelCreds != nil) { - grpc_channel_credentials_release(_channelCreds); - } - // Connectivity monitor is not required for CFStream - char *enableCFStream = getenv(kCFStreamVarName); - if (enableCFStream == nil || enableCFStream[0] != '1') { - [GRPCConnectivityMonitor unregisterObserver:self]; - } -} - // Default initializer. - (nullable instancetype)initWithAddress:(NSString *)address { if (!address) { @@ -86,230 +75,58 @@ static NSMutableDictionary *kHostCache; if ((self = [super init])) { _address = address; - _secure = YES; - kHostCache[address] = self; - _compressAlgorithm = GRPC_COMPRESS_NONE; _retryEnabled = YES; - } - - // Connectivity monitor is not required for CFStream - char *enableCFStream = getenv(kCFStreamVarName); - if (enableCFStream == nil || enableCFStream[0] != '1') { - [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)]; + kHostCache[address] = self; } } return self; } -+ (void)flushChannelCache { - @synchronized(kHostCache) { - [kHostCache enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, GRPCHost *_Nonnull host, - BOOL *_Nonnull stop) { - [host disconnect]; - }]; - } -} - + (void)resetAllHostSettings { @synchronized(kHostCache) { kHostCache = [NSMutableDictionary dictionary]; } } -- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path - serverName:(NSString *)serverName - timeout:(NSTimeInterval)timeout - completionQueue:(GRPCCompletionQueue *)queue { - // The __block attribute is to allow channel take refcount inside @synchronized block. Without - // this attribute, retain of channel object happens after objc_sync_exit in release builds, which - // may result in channel released before used. See grpc/#15033. - __block GRPCChannel *channel; - // This is racing -[GRPCHost disconnect]. - @synchronized(self) { - if (!_channel) { - _channel = [self newChannel]; - } - channel = _channel; - } - return [channel unmanagedCallWithPath:path - serverName:serverName - timeout:timeout - completionQueue:queue]; -} - -- (NSData *)nullTerminatedDataWithString:(NSString *)string { - // dataUsingEncoding: does not return a null-terminated string. - NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; - NSMutableData *nullTerminated = [NSMutableData dataWithData:data]; - [nullTerminated appendBytes:"\0" length:1]; - return nullTerminated; -} - - (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts withPrivateKey:(nullable NSString *)pemPrivateKey withCertChain:(nullable NSString *)pemCertChain error:(NSError **)errorPtr { - static NSData *kDefaultRootsASCII; - static NSError *kDefaultRootsError; - 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; - // 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:&error]; - if (contentInUTF8 == nil) { - kDefaultRootsError = error; - return; - } - kDefaultRootsASCII = [self nullTerminatedDataWithString:contentInUTF8]; - }); - - NSData *rootsASCII; - if (pemRootCerts != nil) { - rootsASCII = [self nullTerminatedDataWithString:pemRootCerts]; - } else { - if (kDefaultRootsASCII == nil) { - if (errorPtr) { - *errorPtr = kDefaultRootsError; - } - NSAssert( - kDefaultRootsASCII, - @"Could not read gRPCCertificates.bundle/roots.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: %@", - kDefaultRootsError); - return NO; - } - rootsASCII = kDefaultRootsASCII; - } - - grpc_channel_credentials *creds; - if (pemPrivateKey == nil && pemCertChain == nil) { - creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL); - } else { - grpc_ssl_pem_key_cert_pair key_cert_pair; - NSData *privateKeyASCII = [self nullTerminatedDataWithString:pemPrivateKey]; - NSData *certChainASCII = [self nullTerminatedDataWithString:pemCertChain]; - key_cert_pair.private_key = privateKeyASCII.bytes; - key_cert_pair.cert_chain = certChainASCII.bytes; - creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL, NULL); - } - - @synchronized(self) { - if (_channelCreds != nil) { - grpc_channel_credentials_release(_channelCreds); - } - _channelCreds = creds; - } - + _pemRootCerts = pemRootCerts; + _pemPrivateKey = pemPrivateKey; + _pemCertChain = pemCertChain; return YES; } -- (NSDictionary *)channelArgsUsingCronet:(BOOL)useCronet { - 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 stringByAppendingFormat:@" %@", userAgent]; - } - args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent; - - if (_secure && _hostNameOverride) { - args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride; - } - - if (_responseSizeLimitOverride) { - args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = _responseSizeLimitOverride; - } - - if (_compressAlgorithm != GRPC_COMPRESS_NONE) { - args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = [NSNumber numberWithInt:_compressAlgorithm]; - } - - if (_keepaliveInterval != 0) { - args[@GRPC_ARG_KEEPALIVE_TIME_MS] = [NSNumber numberWithInt:_keepaliveInterval]; - args[@GRPC_ARG_KEEPALIVE_TIMEOUT_MS] = [NSNumber numberWithInt:_keepaliveTimeout]; - } - - id logContext = self.logContext; - if (logContext != nil) { - args[@GRPC_ARG_MOBILE_LOG_CONTEXT] = logContext; - } - - if (useCronet) { - args[@GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER] = [NSNumber numberWithInt:1]; - } - - if (_retryEnabled == NO) { - args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:0]; - } - - if (_minConnectTimeout > 0) { - args[@GRPC_ARG_MIN_RECONNECT_BACKOFF_MS] = [NSNumber numberWithInt:_minConnectTimeout]; - } - if (_initialConnectBackoff > 0) { - args[@GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS] = [NSNumber numberWithInt:_initialConnectBackoff]; - } - if (_maxConnectBackoff > 0) { - args[@GRPC_ARG_MAX_RECONNECT_BACKOFF_MS] = [NSNumber numberWithInt:_maxConnectBackoff]; - } - - return args; -} - -- (GRPCChannel *)newChannel { - BOOL useCronet = NO; -#ifdef GRPC_COMPILE_WITH_CRONET - useCronet = [GRPCCall isUsingCronet]; -#endif - NSDictionary *args = [self channelArgsUsingCronet:useCronet]; - if (_secure) { - GRPCChannel *channel; - @synchronized(self) { - if (_channelCreds == nil) { - [self setTLSPEMRootCerts:nil withPrivateKey:nil withCertChain:nil error:nil]; - } -#ifdef GRPC_COMPILE_WITH_CRONET - if (useCronet) { - channel = [GRPCChannel secureCronetChannelWithHost:_address channelArgs:args]; - } else -#endif - { - channel = - [GRPCChannel secureChannelWithHost:_address credentials:_channelCreds channelArgs:args]; - } - } - return channel; - } else { - return [GRPCChannel insecureChannelWithHost:_address channelArgs:args]; - } -} - -- (NSString *)hostName { - // TODO(jcanizales): Default to nil instead of _address when Issue #2635 is clarified. - return _hostNameOverride ?: _address; +- (GRPCCallOptions *)callOptions { + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.userAgentPrefix = _userAgentPrefix; + options.responseSizeLimit = _responseSizeLimitOverride; + options.compressAlgorithm = (GRPCCompressAlgorithm)_compressAlgorithm; + options.enableRetry = _retryEnabled; + options.keepaliveInterval = (NSTimeInterval)_keepaliveInterval / 1000; + options.keepaliveTimeout = (NSTimeInterval)_keepaliveTimeout / 1000; + options.connectMinTimeout = (NSTimeInterval)_minConnectTimeout / 1000; + options.connectInitialBackoff = (NSTimeInterval)_initialConnectBackoff / 1000; + options.connectMaxBackoff = (NSTimeInterval)_maxConnectBackoff / 1000; + options.pemRootCert = _pemRootCerts; + options.pemPrivateKey = _pemPrivateKey; + options.pemCertChain = _pemCertChain; + options.hostNameOverride = _hostNameOverride; + options.transportType = _transportType; + options.logContext = _logContext; + + return options; } -- (void)disconnect { - // This is racing -[GRPCHost unmanagedCallWithPath:completionQueue:]. - @synchronized(self) { - _channel = nil; ++ (BOOL)isHostConfigured:(NSString *)address { + // TODO (mxyan): Remove when old API is deprecated + NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]]; + if (hostURL.host && !hostURL.port) { + address = [hostURL.host stringByAppendingString:@":443"]; } -} - -// Flushes the host cache when connectivity status changes or when connection switch between Wifi -// and Cellular data, so that a new call will use a new channel. Otherwise, a new call will still -// use the cached channel which is no longer available and will cause gRPC to hang. -- (void)connectivityChange:(NSNotification *)note { - [self disconnect]; + GRPCHost *cachedHost = kHostCache[address]; + return (cachedHost != nil); } @end diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h new file mode 100644 index 0000000000..905a181ca7 --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h @@ -0,0 +1,35 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#import "GRPCChannelFactory.h" + +@class GRPCChannel; + +NS_ASSUME_NONNULL_BEGIN + +@interface GRPCInsecureChannelFactory : NSObject + ++ (nullable instancetype)sharedInstance; + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableDictionary *)args; + +- (nullable instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m new file mode 100644 index 0000000000..41860bf6ff --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -0,0 +1,48 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GRPCInsecureChannelFactory.h" + +#import "ChannelArgsUtil.h" +#import "GRPCChannel.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation GRPCInsecureChannelFactory + ++ (nullable instancetype)sharedInstance { + static GRPCInsecureChannelFactory *instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] init]; + }); + return instance; +} + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableDictionary *)args { + grpc_channel_args *coreChannelArgs = BuildChannelArgs([args copy]); + grpc_channel *unmanagedChannel = + grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); + FreeChannelArgs(coreChannelArgs); + return unmanagedChannel; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h new file mode 100644 index 0000000000..ab5eee478e --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h @@ -0,0 +1,38 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#import "GRPCChannelFactory.h" + +@class GRPCChannel; + +NS_ASSUME_NONNULL_BEGIN + +@interface GRPCSecureChannelFactory : NSObject + ++ (nullable instancetype)factoryWithPEMRootCerts:(nullable NSString *)rootCerts + privateKey:(nullable NSString *)privateKey + certChain:(nullable NSString *)certChain + error:(NSError **)errorPtr; + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableDictionary *)args; + +- (nullable instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m new file mode 100644 index 0000000000..a0d56e4bdc --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -0,0 +1,129 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GRPCSecureChannelFactory.h" + +#include + +#import "ChannelArgsUtil.h" +#import "GRPCChannel.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation GRPCSecureChannelFactory { + grpc_channel_credentials *_channelCreds; +} + ++ (nullable instancetype)factoryWithPEMRootCerts:(nullable NSString *)rootCerts + privateKey:(nullable NSString *)privateKey + certChain:(nullable NSString *)certChain + error:(NSError **)errorPtr { + return [[self alloc] initWithPEMRootCerts:rootCerts + privateKey:privateKey + certChain:certChain + error:errorPtr]; +} + +- (NSData *)nullTerminatedDataWithString:(NSString *)string { + // dataUsingEncoding: does not return a null-terminated string. + NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + NSMutableData *nullTerminated = [NSMutableData dataWithData:data]; + [nullTerminated appendBytes:"\0" length:1]; + return nullTerminated; +} + +- (nullable instancetype)initWithPEMRootCerts:(nullable NSString *)rootCerts + privateKey:(nullable NSString *)privateKey + certChain:(nullable NSString *)certChain + error:(NSError **)errorPtr { + static NSData *kDefaultRootsASCII; + static NSError *kDefaultRootsError; + 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; + // 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:&error]; + if (contentInUTF8 == nil) { + kDefaultRootsError = error; + return; + } + kDefaultRootsASCII = [self nullTerminatedDataWithString:contentInUTF8]; + }); + + NSData *rootsASCII; + if (rootCerts != nil) { + rootsASCII = [self nullTerminatedDataWithString:rootCerts]; + } else { + if (kDefaultRootsASCII == nil) { + if (errorPtr) { + *errorPtr = kDefaultRootsError; + } + NSAssert( + kDefaultRootsASCII, + @"Could not read gRPCCertificates.bundle/roots.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: %@", + kDefaultRootsError); + return nil; + } + rootsASCII = kDefaultRootsASCII; + } + + grpc_channel_credentials *creds; + if (privateKey == nil && certChain == nil) { + creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL); + } else { + grpc_ssl_pem_key_cert_pair key_cert_pair; + NSData *privateKeyASCII = [self nullTerminatedDataWithString:privateKey]; + NSData *certChainASCII = [self nullTerminatedDataWithString:certChain]; + key_cert_pair.private_key = privateKeyASCII.bytes; + key_cert_pair.cert_chain = certChainASCII.bytes; + creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL, NULL); + } + + if ((self = [super init])) { + _channelCreds = creds; + } + return self; +} + +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSMutableArray *)args { + grpc_channel_args *coreChannelArgs = BuildChannelArgs([args copy]); + grpc_channel *unmanagedChannel = + grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); + FreeChannelArgs(coreChannelArgs); + return unmanagedChannel; +} + +- (void)dealloc { + if (_channelCreds != nil) { + grpc_channel_credentials_release(_channelCreds); + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h index f711850c2f..19aa5367c7 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h @@ -74,9 +74,8 @@ @interface GRPCWrappedCall : NSObject - (instancetype)initWithHost:(NSString *)host - serverName:(NSString *)serverName path:(NSString *)path - timeout:(NSTimeInterval)timeout NS_DESIGNATED_INITIALIZER; + callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; - (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void (^)(void))errorHandler; diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 7781d27ca4..1c03bc9efd 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -23,6 +23,7 @@ #include #include +#import "GRPCChannel.h" #import "GRPCCompletionQueue.h" #import "GRPCHost.h" #import "NSData+GRPC.h" @@ -235,31 +236,28 @@ @implementation GRPCWrappedCall { GRPCCompletionQueue *_queue; + GRPCChannel *_channel; grpc_call *_call; } - (instancetype)init { - return [self initWithHost:nil serverName:nil path:nil timeout:0]; + return [self initWithHost:nil path:nil callOptions:[[GRPCCallOptions alloc] init]]; } - (instancetype)initWithHost:(NSString *)host - serverName:(NSString *)serverName path:(NSString *)path - timeout:(NSTimeInterval)timeout { + callOptions:(GRPCCallOptions *)callOptions { if (!path || !host) { [NSException raise:NSInvalidArgumentException format:@"path and host cannot be nil."]; } - if (self = [super init]) { + if ((self = [super init])) { // Each completion queue consumes one thread. There's a trade to be made between creating and // consuming too many threads and having contention of multiple calls in a single completion // queue. Currently we use a singleton queue. _queue = [GRPCCompletionQueue completionQueue]; - - _call = [[GRPCHost hostWithAddress:host] unmanagedCallWithPath:path - serverName:serverName - timeout:timeout - completionQueue:_queue]; + _channel = [GRPCChannel channelWithHost:host callOptions:callOptions]; + _call = [_channel unmanagedCallWithPath:path completionQueue:_queue callOptions:callOptions]; if (_call == NULL) { return nil; } @@ -313,6 +311,8 @@ - (void)dealloc { grpc_call_unref(_call); + [_channel unmanagedCallUnref]; + _channel = nil; } @end -- cgit v1.2.3 From 21c32e8f013986d6b120c852b34e058c82a4cf6d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 16:33:41 -0700 Subject: Remove redundant forward declaration --- src/objective-c/GRPCClient/GRPCCall.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 3f6ec75c04..f396ffe599 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -39,8 +39,6 @@ #include "GRPCCallOptions.h" -@class GRPCCallOptions; - #pragma mark gRPC errors /** Domain of NSError objects produced by gRPC. */ -- cgit v1.2.3 From 553664f59bc947d48c73e6c1976e054fe35147f5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 16:34:21 -0700 Subject: Make dispatcheQueue of responseHandler required --- src/objective-c/GRPCClient/GRPCCall.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index f396ffe599..64a6df3134 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -150,14 +150,18 @@ extern id const kGRPCTrailersKey; /** An object can implement this protocol to receive responses from server from a call. */ @protocol GRPCResponseHandler + @optional + /** Issued when initial metadata is received from the server. */ - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; + /** * Issued when a message is received from the server. The message may be raw data from the server * (when using \a GRPCCall2 directly) or deserialized proto object (when using \a ProtoRPC). */ - (void)receivedMessage:(id)message; + /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error @@ -166,9 +170,13 @@ extern id const kGRPCTrailersKey; */ - (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error; +@required + /** * All the responses must be issued to a user-provided dispatch queue. This property specifies the - * dispatch queue to be used for issuing the notifications. + * dispatch queue to be used for issuing the notifications. A serial queue should be provided if + * the order of responses (initial metadata, message, message, ..., message, trailing metadata) + * needs to be maintained. */ @property(atomic, readonly) dispatch_queue_t dispatchQueue; -- cgit v1.2.3 From 5715719afb061feb3c7de931cc8e7126bc9560e5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 16:36:09 -0700 Subject: Make multiple -init and +new UNAVAILABLE; identify designated initializer --- src/objective-c/GRPCClient/GRPCCall.h | 6 +++++- src/objective-c/ProtoRPC/ProtoRPC.h | 12 ++++++++++-- src/objective-c/ProtoRPC/ProtoService.h | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 64a6df3134..2ee181b93b 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -190,8 +190,10 @@ extern id const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + /** Initialize with all properties. */ -- (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety; +- (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety NS_DESIGNATED_INITIALIZER; /** The host serving the RPC service. */ @property(copy, readonly) NSString *host; @@ -214,6 +216,8 @@ extern id const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + /** * Designated initializer for a call. * \param requestOptions Protobuf generated parameters for the call. diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 1a27cac2a3..a045ef10a6 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -26,6 +26,10 @@ /** A unary-request RPC call with Protobuf. */ @interface GRPCUnaryProtoCall : NSObject +- (instancetype)init NS_UNAVAILABLE; + ++ (instancetype)new NS_UNAVAILABLE; + /** * Users should not use this initializer directly. Call objects will be created, initialized, and * returned to users by methods of the generated service. @@ -34,7 +38,7 @@ message:(GPBMessage *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions - responseClass:(Class)responseClass; + responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** Cancel the call at best effort. */ - (void)cancel; @@ -44,6 +48,10 @@ /** A client-streaming RPC call with Protobuf. */ @interface GRPCStreamingProtoCall : NSObject +- (instancetype)init NS_UNAVAILABLE; + ++ (instancetype)new NS_UNAVAILABLE; + /** * Users should not use this initializer directly. Call objects will be created, initialized, and * returned to users by methods of the generated service. @@ -51,7 +59,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions - responseClass:(Class)responseClass; + responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** Cancel the call at best effort. */ - (void)cancel; diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index 2105de78a3..2985c5cb2d 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -30,6 +30,10 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoService : NSObject +- (instancetype)init NS_UNAVAILABLE; + ++ (instancetype)new NS_UNAVAILABLE; + - (instancetype)initWithHost : (NSString *)host packageName : (NSString *)packageName serviceName : (NSString *)serviceName callOptions -- cgit v1.2.3 From 0865a6098880b91235348cb9ffe49ddbb13ebdc6 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 16:37:08 -0700 Subject: Typo and doc fix --- src/objective-c/GRPCClient/GRPCCall.h | 3 ++- src/objective-c/GRPCClient/GRPCCallOptions.m | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 2ee181b93b..01d04807cc 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -228,7 +228,8 @@ extern id const kGRPCTrailersKey; handler:(id)handler callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; /** - * Convevience initializer for a call that uses default call options. + * Convenience initializer for a call that uses default call options (see GRPCCallOptions.m for + * the default options). */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions handler:(id)handler; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index ee76c2a642..072b980af4 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -18,6 +18,7 @@ #import "GRPCCallOptions.h" +// The default values for the call options. static NSString *const kDefaultServerAuthority = nil; static const NSTimeInterval kDefaultTimeout = 0; static NSDictionary *const kDefaultInitialMetadata = nil; -- cgit v1.2.3 From efa359b02b0122c90decfbcd5e1659198b565b4e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 16:50:12 -0700 Subject: Rename handler->responseHandler in function signature --- src/objective-c/GRPCClient/GRPCCall.h | 6 +++--- src/objective-c/GRPCClient/GRPCCall.m | 8 ++++---- src/objective-c/ProtoRPC/ProtoRPC.m | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 01d04807cc..8554860ade 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -221,18 +221,18 @@ extern id const kGRPCTrailersKey; /** * Designated initializer for a call. * \param requestOptions Protobuf generated parameters for the call. - * \param handler The object to which responses should be issed. + * \param responseHandler The object to which responses should be issed. * \param callOptions Options for the call. */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - handler:(id)handler + responseHandler:(id)responseHandler callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; /** * Convenience initializer for a call that uses default call options (see GRPCCallOptions.m for * the default options). */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - handler:(id)handler; + responseHandler:(id)responseHandler; /** * Starts the call. Can only be called once. diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 519f91e522..6eb9e2e406 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -95,7 +95,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - handler:(id)handler + responseHandler:(id)responseHandler callOptions:(GRPCCallOptions *)callOptions { if (!requestOptions || !requestOptions.host || !requestOptions.path) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; @@ -104,7 +104,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; if ((self = [super init])) { _requestOptions = [requestOptions copy]; _callOptions = [callOptions copy]; - _handler = handler; + _handler = responseHandler; _initialMetadataPublished = NO; _pipe = [GRXBufferedPipe pipe]; _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); @@ -114,8 +114,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - handler:(id)handler { - return [self initWithRequestOptions:requestOptions handler:handler callOptions:nil]; + responseHandler:(id)responseHandler { + return [self initWithRequestOptions:requestOptions responseHandler:responseHandler callOptions:nil]; } - (void)start { diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index f89c160650..34fd54a216 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -86,7 +86,7 @@ - (void)start { _call = [[GRPCCall2 alloc] initWithRequestOptions:_requestOptions - handler:self + responseHandler:self callOptions:_callOptions]; [_call start]; } -- cgit v1.2.3 From eab498bef453e221abd4602e6ceff16da659b3c1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 16:44:00 -0700 Subject: Handle GRPCCall2:start: twice --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/GRPCClient/GRPCCall.m | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 8554860ade..5f6afab08c 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -235,7 +235,7 @@ extern id const kGRPCTrailersKey; responseHandler:(id)responseHandler; /** - * Starts the call. Can only be called once. + * Starts the call. This function should only be called once; additional calls will be discarded. */ - (void)start; diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 6eb9e2e406..9cb4aa34c2 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -92,6 +92,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; BOOL _initialMetadataPublished; GRXBufferedPipe *_pipe; dispatch_queue_t _dispatchQueue; + bool _started; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -108,6 +109,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; _initialMetadataPublished = NO; _pipe = [GRXBufferedPipe pipe]; _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + _started = NO; } return self; @@ -120,6 +122,10 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)start { dispatch_async(_dispatchQueue, ^{ + if (self->_started) { + return; + } + self->_started = YES; if (!self->_callOptions) { self->_callOptions = [[GRPCCallOptions alloc] init]; } -- cgit v1.2.3 From fe8a899b631b3fd804b59ca32639ef2a14bb597f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 16:56:00 -0700 Subject: Rename writeWithData to writeData --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/ProtoRPC/ProtoRPC.m | 2 +- src/objective-c/tests/GRPCClientTests.m | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 5f6afab08c..c8f3919a63 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -249,7 +249,7 @@ extern id const kGRPCTrailersKey; /** * Send a message to the server. Data are sent as raw bytes in gRPC message frames. */ -- (void)writeWithData:(NSData *)data; +- (void)writeData:(NSData *)data; /** * Finish the RPC request and half-close the call. The server may still send messages and/or diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 9cb4aa34c2..7fdc8fcac2 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -206,7 +206,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; }); } -- (void)writeWithData:(NSData *)data { +- (void)writeData:(NSData *)data { dispatch_async(_dispatchQueue, ^{ [self->_pipe writeValue:data]; }); diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 34fd54a216..957d636534 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -120,7 +120,7 @@ dispatch_async(_dispatchQueue, ^{ if (_call) { - [_call writeWithData:[message data]]; + [_call writeData:[message data]]; } }); } diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index bad22d30cb..db7265c712 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -332,7 +332,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; callOptions:options]; [call start]; - [call writeWithData:[request data]]; + [call writeData:[request data]]; [call finish]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; @@ -495,7 +495,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } }] callOptions:options]; - [call writeWithData:[NSData data]]; + [call writeData:[NSData data]]; [call start]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; @@ -632,7 +632,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; callOptions:options]; [call start]; - [call writeWithData:[request data]]; + [call writeData:[request data]]; [call finish]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; -- cgit v1.2.3 From 50dac6721425b225e3e031251c7eb888ec61f07e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 18:09:01 -0700 Subject: Update GRPCCall2:cancel: docs --- src/objective-c/GRPCClient/GRPCCall.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index c8f3919a63..354bdb7cfa 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -240,9 +240,9 @@ extern id const kGRPCTrailersKey; - (void)start; /** - * Cancel the request of this call at best effort; notifies the server that the RPC should be - * cancelled, and issue callback to the user with an error code CANCELED if the call is not - * finished. + * Cancel the request of this call at best effort. It attempts to notify the server that the RPC + * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code + * CANCELED if no other error code has already been issued. */ - (void)cancel; -- cgit v1.2.3 From 161dc27b2d3882ab3f8a8bcc26733a729e034583 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 18:09:42 -0700 Subject: Copy string fix --- src/objective-c/GRPCClient/GRPCCall.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 7fdc8fcac2..c0413ec6c2 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -68,8 +68,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { if ((self = [super init])) { - _host = host; - _path = path; + _host = [host copy]; + _path = [path copy]; _safety = safety; } return self; @@ -77,7 +77,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (id)copyWithZone:(NSZone *)zone { GRPCRequestOptions *request = - [[GRPCRequestOptions alloc] initWithHost:[_host copy] path:[_path copy] safety:_safety]; + [[GRPCRequestOptions alloc] initWithHost:_host path:_path safety:_safety]; return request; } -- cgit v1.2.3 From 413077101eab400635732b813da4f1e4a5b69c5a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 18:10:21 -0700 Subject: requestOptions precondition check polishing --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index c0413ec6c2..c9ee508486 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -98,7 +98,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler callOptions:(GRPCCallOptions *)callOptions { - if (!requestOptions || !requestOptions.host || !requestOptions.path) { + if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; } -- cgit v1.2.3 From f18b08a1a4454f8232c2815f0110427c1a86878f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 10 Oct 2018 18:55:28 -0700 Subject: Check if optional method of GRPCCallOptions are implemented --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/GRPCClient/GRPCCall.m | 32 +++++++++++++++++++++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 354bdb7cfa..304fb17cca 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -149,7 +149,7 @@ extern id const kGRPCHeadersKey; extern id const kGRPCTrailersKey; /** An object can implement this protocol to receive responses from server from a call. */ -@protocol GRPCResponseHandler +@protocol GRPCResponseHandler @optional diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index c9ee508486..e1039a1b2a 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -149,12 +149,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; } if (headers) { dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:headers]; + if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + [handler receivedInitialMetadata:headers]; + } }); } if (value) { dispatch_async(handler.dispatchQueue, ^{ - [handler receivedMessage:value]; + if ([handler respondsToSelector:@selector(receivedMessage:)]) { + [handler receivedMessage:value]; + } }); } } @@ -171,11 +175,15 @@ const char *kCFStreamVarName = "grpc_cfstream"; } if (headers) { dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:headers]; + if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + [handler receivedInitialMetadata:headers]; + } }); } dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + [handler closedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; + } }); } }); @@ -193,13 +201,15 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (self->_handler) { id handler = self->_handler; dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + [handler closedWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + } }); self->_handler = nil; } -- cgit v1.2.3 From 7b08066d8ff5cca57ee6eaa4cae014d07e4aa8e1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 10:56:51 -0700 Subject: Fix CI failures --- src/objective-c/tests/GRPCClientTests.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index db7265c712..8a4eddb1b7 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -306,7 +306,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; options.oauth2AccessToken = @"bogusToken"; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:callRequest - handler:[[ClientTestsBlockCallbacks alloc] + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) { init_md = initialMetadata; } @@ -446,7 +446,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; options.initialMetadata = headers; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:request - handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^( + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^( NSDictionary *initialMetadata) { NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"]; // Test the regex is correct @@ -609,7 +609,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; options.transportType = GRPCTransportTypeInsecure; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions - handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id message) { NSData *data = (NSData *)message; XCTAssertNotNil(data, @"nil value received as response."); @@ -739,7 +739,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions - handler: + responseHandler: [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id data) { XCTFail( @@ -835,9 +835,9 @@ static GRPCProtoMethod *kFullDuplexCallMethod; const double kMargin = 0.1; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; - NSString *const kDummyAddress = [NSString stringWithFormat:@"8.8.8.8:1"]; + NSString *const kDummyAddress = [NSString stringWithFormat:@"127.0.0.1:10000"]; GRPCRequestOptions *requestOptions = - [[GRPCRequestOptions alloc] initWithHost:kDummyAddress path:@"" safety:GRPCCallSafetyDefault]; + [[GRPCRequestOptions alloc] initWithHost:kDummyAddress path:@"/dummy/path" safety:GRPCCallSafetyDefault]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.connectMinTimeout = timeout; options.connectInitialBackoff = backoff; @@ -846,7 +846,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; NSDate *startTime = [NSDate date]; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions - handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id data) { XCTFail(@"Received message. Should not reach here."); } -- cgit v1.2.3 From 5d16c2ff92eb49319d9028cbe99bb80bf41e0578 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 11:20:26 -0700 Subject: Move issuance of response in helper functions --- src/objective-c/GRPCClient/GRPCCall.m | 54 +++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index e1039a1b2a..1e9bc41b41 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -141,25 +141,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; id responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(id value) { dispatch_async(self->_dispatchQueue, ^{ if (self->_handler) { - id handler = self->_handler; NSDictionary *headers = nil; if (!self->_initialMetadataPublished) { headers = self->_call.responseHeaders; self->_initialMetadataPublished = YES; } if (headers) { - dispatch_async(handler.dispatchQueue, ^{ - if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { - [handler receivedInitialMetadata:headers]; - } - }); + [self issueInitialMetadata:headers]; } if (value) { - dispatch_async(handler.dispatchQueue, ^{ - if ([handler respondsToSelector:@selector(receivedMessage:)]) { - [handler receivedMessage:value]; - } - }); + [self issueMessage:value]; } } }); @@ -167,24 +158,15 @@ const char *kCFStreamVarName = "grpc_cfstream"; completionHandler:^(NSError *errorOrNil) { dispatch_async(self->_dispatchQueue, ^{ if (self->_handler) { - id handler = self->_handler; NSDictionary *headers = nil; if (!self->_initialMetadataPublished) { headers = self->_call.responseHeaders; self->_initialMetadataPublished = YES; } if (headers) { - dispatch_async(handler.dispatchQueue, ^{ - if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { - [handler receivedInitialMetadata:headers]; - } - }); + [self issueInitialMetadata:headers]; } - dispatch_async(handler.dispatchQueue, ^{ - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [handler closedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; - } - }); + [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; } }); }]; @@ -230,6 +212,34 @@ const char *kCFStreamVarName = "grpc_cfstream"; }); } +- (void)issueInitialMetadata:(NSDictionary *)initialMetadata { + id handler = self->_handler; + if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedInitialMetadata:initialMetadata]; + }); + } +} + +- (void)issueMessage:(id)message { + id handler = self->_handler; + if ([handler respondsToSelector:@selector(receivedMessage:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedMessage:message]; + }); + } +} + +- (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata + error:(NSError *)error { + id handler = self->_handler; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:self->_call.responseTrailers error:error]; + }); + } +} + @end // The following methods of a C gRPC call object aren't reentrant, and thus -- cgit v1.2.3 From 92e81c80efb8d5dcbc6362206be09b2ef9107a2b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 11:33:27 -0700 Subject: Add comment on clearing GRPCCall2._handler --- src/objective-c/GRPCClient/GRPCCall.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 1e9bc41b41..ace149fad5 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -167,6 +167,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; [self issueInitialMetadata:headers]; } [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; + + // Clean up _handler so that no more responses are reported to the handler. + self->_handler = nil; } }); }]; @@ -193,6 +196,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; }]]; } }); + + // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; } }); -- cgit v1.2.3 From b634447d2cb762b47365218e1affd317a4ccd8b3 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:15:45 -0700 Subject: Resetting _call and _handler on finish --- src/objective-c/GRPCClient/GRPCCall.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index ace149fad5..d0495f6cbf 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -170,6 +170,13 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; + + // If server terminated the call we should close the send path too. + if (self->_call) { + [self->_pipe writesFinishedWithError:nil]; + self->_call = nil; + self->_pipe = nil; + } } }); }]; @@ -182,6 +189,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (self->_call) { [self->_call cancel]; self->_call = nil; + self->_pipe = nil; } if (self->_handler) { id handler = self->_handler; @@ -214,6 +222,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (self->_call) { [self->_pipe writesFinishedWithError:nil]; } + self->_call = nil; + self->_pipe = nil; }); } -- cgit v1.2.3 From aabce5e19ca93c54fc0560116e0e8cb53dabdc19 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:16:09 -0700 Subject: Initialize flag --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index d0495f6cbf..40db83155b 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -541,7 +541,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)sendHeaders { // TODO (mxyan): Remove after deprecated methods are removed - uint32_t callSafetyFlags; + uint32_t callSafetyFlags = 0; switch (_callSafety) { case GRPCCallSafetyDefault: callSafetyFlags = 0; -- cgit v1.2.3 From fb9d054ac7da0cad67cb7431fc91823c7349df33 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:16:35 -0700 Subject: Check string length --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 40db83155b..0f2c367331 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -738,7 +738,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } else { callOptions = [[GRPCMutableCallOptions alloc] init]; } - if (_serverName != nil) { + if (_serverName.length != 0) { callOptions.serverAuthority = _serverName; } if (_timeout != 0) { -- cgit v1.2.3 From bca7e68ccbf15eab3d3a8a09d0e3d50d7db49cf9 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:17:40 -0700 Subject: use strong self for authTokenProvider --- src/objective-c/GRPCClient/GRPCCall.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 0f2c367331..28d3b52d5e 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -761,15 +761,13 @@ const char *kCFStreamVarName = "grpc_cfstream"; } if (_callOptions.authTokenProvider != nil) { self.isWaitingForToken = YES; - __weak typeof(self) weakSelf = self; [self.tokenProvider getTokenWithHandler:^(NSString *token) { - typeof(self) strongSelf = weakSelf; - if (strongSelf && strongSelf.isWaitingForToken) { + if (self.isWaitingForToken) { if (token) { - strongSelf->_fetchedOauth2AccessToken = token; + self->_fetchedOauth2AccessToken = [token copy]; } - [strongSelf startCallWithWriteable:writeable]; - strongSelf.isWaitingForToken = NO; + [self startCallWithWriteable:writeable]; + self.isWaitingForToken = NO; } }]; } else { -- cgit v1.2.3 From 8592dc27223e9ec41f4f52634f662c4485bd119b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:31:07 -0700 Subject: Rename GRPCTransportTypeDefault to GRPCTransportTypeChttp2CFStream --- src/objective-c/GRPCClient/GRPCCallOptions.h | 2 +- src/objective-c/GRPCClient/GRPCCallOptions.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- src/objective-c/tests/ChannelTests/ChannelPoolTest.m | 2 +- src/objective-c/tests/ChannelTests/ChannelTests.m | 4 ++-- src/objective-c/tests/InteropTests.m | 2 +- src/objective-c/tests/InteropTestsLocalSSL.m | 2 +- .../tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m | 2 +- src/objective-c/tests/InteropTestsRemote.m | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 75b320ca6d..1093044c0c 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -42,7 +42,7 @@ typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) { // The transport to be used by a gRPC call typedef NS_ENUM(NSInteger, GRPCTransportType) { // gRPC internal HTTP/2 stack with BoringSSL - GRPCTransportTypeDefault = 0, + GRPCTransportTypeChttp2BoringSSL = 0, // Cronet stack GRPCTransportTypeCronet, // Insecure channel. FOR TEST ONLY! diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 072b980af4..0216342817 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -37,7 +37,7 @@ static NSString *const kDefaultPemPrivateKey = nil; static NSString *const kDefaultPemCertChain = nil; static NSString *const kDefaultOauth2AccessToken = nil; static const id kDefaultAuthTokenProvider = nil; -static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeDefault; +static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2BoringSSL; static NSString *const kDefaultHostNameOverride = nil; static const id kDefaultLogContext = nil; static NSString *kDefaultChannelPoolDomain = nil; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index b5f0949ef7..340f4f3c83 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -49,7 +49,7 @@ const NSTimeInterval kChannelDestroyDelay = 30; id factory; GRPCTransportType type = _callOptions.transportType; switch (type) { - case GRPCTransportTypeDefault: + case GRPCTransportTypeChttp2BoringSSL: // TODO (mxyan): Remove when the API is deprecated #ifdef GRPC_COMPILE_WITH_CRONET if (![GRPCCall isUsingCronet]) { diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index 3b6b10b1a5..9e1c9eca74 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -127,7 +127,7 @@ NSString *kDummyHost = @"dummy.host"; GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; options1.transportType = GRPCTransportTypeInsecure; GRPCMutableCallOptions *options2 = [[GRPCMutableCallOptions alloc] init]; - options2.transportType = GRPCTransportTypeDefault; + options2.transportType = GRPCTransportTypeChttp2BoringSSL; GRPCChannelConfiguration *config1 = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; GRPCChannelConfiguration *config2 = diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index 0a8b7ae6ee..64c3356b13 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -72,7 +72,7 @@ - (void)testDifferentChannelParameters { NSString *host = @"grpc-test.sandbox.googleapis.com"; GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; - options1.transportType = GRPCTransportTypeDefault; + options1.transportType = GRPCTransportTypeChttp2BoringSSL; NSMutableDictionary *args = [NSMutableDictionary new]; args[@"abc"] = @"xyz"; options1.additionalChannelArgs = [args copy]; @@ -80,7 +80,7 @@ options2.transportType = GRPCTransportTypeInsecure; options2.additionalChannelArgs = [args copy]; GRPCMutableCallOptions *options3 = [[GRPCMutableCallOptions alloc] init]; - options3.transportType = GRPCTransportTypeDefault; + options3.transportType = GRPCTransportTypeChttp2BoringSSL; args[@"def"] = @"uvw"; options3.additionalChannelArgs = [args copy]; GRPCChannel *channel1 = [GRPCChannel channelWithHost:host callOptions:options1]; diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 54af7036c3..16d5040a73 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -144,7 +144,7 @@ BOOL isRemoteInteropTest(NSString *host) { } + (GRPCTransportType)transportType { - return GRPCTransportTypeDefault; + return GRPCTransportTypeChttp2BoringSSL; } + (NSString *)pemRootCert { diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m index eb72dd1d31..997dd87eee 100644 --- a/src/objective-c/tests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTestsLocalSSL.m @@ -57,7 +57,7 @@ static int32_t kLocalInteropServerOverhead = 10; } + (GRPCTransportType)transportType { - return GRPCTransportTypeDefault; + return GRPCTransportTypeChttp2BoringSSL; } - (void)setUp { diff --git a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m index eb0ba7f34b..b1d663584c 100644 --- a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m +++ b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m @@ -114,7 +114,7 @@ dispatch_once_t initCronet; XCTAssertNil(error); options = [[GRPCCallOptions alloc] init]; - options.transportType = GRPCTransportTypeDefault; + options.transportType = GRPCTransportTypeChttp2BoringSSL; options.pemRootCert = certs; options.hostNameOverride = @"foo.test.google.fr"; _localSSLService.options = options; diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m index 516a1f432a..30670facad 100644 --- a/src/objective-c/tests/InteropTestsRemote.m +++ b/src/objective-c/tests/InteropTestsRemote.m @@ -59,7 +59,7 @@ static int32_t kRemoteInteropServerOverhead = 12; } #else + (GRPCTransportType)transportType { - return GRPCTransportTypeDefault; + return GRPCTransportTypeChttp2BoringSSL; } #endif -- cgit v1.2.3 From 96709ecb8cde75f2750d96dc288167292790eb5a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:34:24 -0700 Subject: Fix another NSString* != nil to NSString.length != 0 --- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 340f4f3c83..2b08eb8d5e 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -131,7 +131,7 @@ const NSTimeInterval kChannelDestroyDelay = 30; args[@GRPC_ARG_MOBILE_LOG_CONTEXT] = _callOptions.logContext; } - if (_callOptions.channelPoolDomain != nil) { + if (_callOptions.channelPoolDomain.length != 0) { args[@GRPC_ARG_CHANNEL_POOL_DOMAIN] = _callOptions.channelPoolDomain; } -- cgit v1.2.3 From 0d4ac971df9d2a795eac674e0a105d0c51f7387b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:45:43 -0700 Subject: Restrict NSTimeInterval parameters to non-negative --- src/objective-c/GRPCClient/GRPCCallOptions.h | 29 ++++++++++++---------- src/objective-c/GRPCClient/GRPCCallOptions.m | 36 +++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 1093044c0c..70dd7741fd 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -120,15 +120,15 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { */ @property(readonly) BOOL enableRetry; -/** - * HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two - * PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the - * call should wait for PING ACK. If PING ACK is not received after this period, the call fails. - */ +// HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two +// PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the +// call should wait for PING ACK. If PING ACK is not received after this period, the call fails. +// Negative values are not allowed. @property(readonly) NSTimeInterval keepaliveInterval; @property(readonly) NSTimeInterval keepaliveTimeout; -// Parameters for connection backoff. For details of gRPC's backoff behavior, refer to +// Parameters for connection backoff. Negative values are not allowed. +// For details of gRPC's backoff behavior, refer to // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md @property(readonly) NSTimeInterval connectMinTimeout; @property(readonly) NSTimeInterval connectInitialBackoff; @@ -203,7 +203,8 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed - * within \a timeout seconds. A negative value is not allowed. + * within \a timeout seconds. Negative value is invalid; setting the parameter to negative value + * will reset the parameter to 0. */ @property(readwrite) NSTimeInterval timeout; @@ -249,15 +250,17 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { */ @property(readwrite) BOOL enableRetry; -/** - * HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two - * PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the - * call should wait for PING ACK. If PING ACK is not received after this period, the call fails. - */ +// HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two +// PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the +// call should wait for PING ACK. If PING ACK is not received after this period, the call fails. +// Negative values are invalid; setting these parameters to negative value will reset the +// corresponding parameter to 0. @property(readwrite) NSTimeInterval keepaliveInterval; @property(readwrite) NSTimeInterval keepaliveTimeout; -// Parameters for connection backoff. For details of gRPC's backoff behavior, refer to +// Parameters for connection backoff. Negative value is invalid; setting the parameters to negative +// value will reset corresponding parameter to 0. +// For details of gRPC's backoff behavior, refer to // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md @property(readwrite) NSTimeInterval connectMinTimeout; @property(readwrite) NSTimeInterval connectInitialBackoff; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 0216342817..1f25df7d53 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -342,7 +342,11 @@ static NSUInteger kDefaultChannelId = 0; } - (void)setTimeout:(NSTimeInterval)timeout { - _timeout = timeout; + if (timeout < 0) { + _timeout = 0; + } else { + _timeout = timeout; + } } - (void)setOauth2AccessToken:(NSString *)oauth2AccessToken { @@ -374,23 +378,43 @@ static NSUInteger kDefaultChannelId = 0; } - (void)setKeepaliveInterval:(NSTimeInterval)keepaliveInterval { - _keepaliveInterval = keepaliveInterval; + if (keepaliveInterval < 0) { + _keepaliveInterval = 0; + } else { + _keepaliveInterval = keepaliveInterval; + } } - (void)setKeepaliveTimeout:(NSTimeInterval)keepaliveTimeout { - _keepaliveTimeout = keepaliveTimeout; + if (keepaliveTimeout < 0) { + _keepaliveTimeout = 0; + } else { + _keepaliveTimeout = keepaliveTimeout; + } } - (void)setConnectMinTimeout:(NSTimeInterval)connectMinTimeout { - _connectMinTimeout = connectMinTimeout; + if (connectMinTimeout < 0) { + connectMinTimeout = 0; + } else { + _connectMinTimeout = connectMinTimeout; + } } - (void)setConnectInitialBackoff:(NSTimeInterval)connectInitialBackoff { - _connectInitialBackoff = connectInitialBackoff; + if (connectInitialBackoff < 0) { + _connectInitialBackoff = 0; + } else { + _connectInitialBackoff = connectInitialBackoff; + } } - (void)setConnectMaxBackoff:(NSTimeInterval)connectMaxBackoff { - _connectMaxBackoff = connectMaxBackoff; + if (connectMaxBackoff < 0) { + _connectMaxBackoff = 0; + } else { + _connectMaxBackoff = connectMaxBackoff; + } } - (void)setAdditionalChannelArgs:(NSDictionary *)additionalChannelArgs { -- cgit v1.2.3 From a397862fd56bca95da49062b7ca622a0823bc15a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 13:52:24 -0700 Subject: property attribute fixes --- src/objective-c/GRPCClient/GRPCCallOptions.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 70dd7741fd..abfe396511 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -64,7 +64,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * :authority header field of the call and performs an extra check that server's certificate * matches the :authority header. */ -@property(readonly) NSString *serverAuthority; +@property(copy, readonly) NSString *serverAuthority; /** * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to @@ -91,7 +91,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * Initial metadata key-value pairs that should be included in the request. */ -@property(copy, readwrite) NSDictionary *initialMetadata; +@property(copy, readonly) NSDictionary *initialMetadata; // Channel parameters; take into account of channel signature. @@ -198,7 +198,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * :authority header field of the call and performs an extra check that server's certificate * matches the :authority header. */ -@property(readwrite) NSString *serverAuthority; +@property(copy, readwrite) NSString *serverAuthority; /** * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to -- cgit v1.2.3 From 2c1c22c3f1b9c0fe36589da691fbabc60ad1aa25 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 14:31:05 -0700 Subject: Do not nullify GRPCCall2._call on half-close --- src/objective-c/GRPCClient/GRPCCall.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 28d3b52d5e..36cb71399c 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -171,7 +171,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; - // If server terminated the call we should close the send path too. if (self->_call) { [self->_pipe writesFinishedWithError:nil]; self->_call = nil; @@ -222,7 +221,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (self->_call) { [self->_pipe writesFinishedWithError:nil]; } - self->_call = nil; self->_pipe = nil; }); } @@ -247,10 +245,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - id handler = self->_handler; + id handler = _handler; + NSDictionary *trailers = _call.responseTrailers; if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:self->_call.responseTrailers error:error]; + [handler closedWithTrailingMetadata:trailers error:error]; }); } } -- cgit v1.2.3 From 0fc040d19acc960ed3ab331ed92b38b43d32a284 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 14:33:00 -0700 Subject: Rename pemXxx parameters to PEMXxx --- src/objective-c/GRPCClient/GRPCCallOptions.h | 12 ++-- src/objective-c/GRPCClient/GRPCCallOptions.m | 84 +++++++++++----------- .../GRPCClient/private/GRPCChannelPool.m | 24 +++---- src/objective-c/GRPCClient/private/GRPCHost.m | 14 ++-- src/objective-c/tests/InteropTests.h | 2 +- src/objective-c/tests/InteropTests.m | 8 +-- src/objective-c/tests/InteropTestsLocalCleartext.m | 2 +- src/objective-c/tests/InteropTestsLocalSSL.m | 2 +- .../InteropTestsMultipleChannels.m | 2 +- src/objective-c/tests/InteropTestsRemote.m | 2 +- 10 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index abfe396511..ea7c1bf22d 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -146,17 +146,17 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default * root certificates. */ -@property(copy, readonly) NSString *pemRootCert; +@property(copy, readonly) NSString *PEMRootCertificates; /** * PEM format private key for client authentication, if required by the server. */ -@property(copy, readonly) NSString *pemPrivateKey; +@property(copy, readonly) NSString *PEMPrivateKey; /** * PEM format certificate chain for client authentication, if required by the server. */ -@property(copy, readonly) NSString *pemCertChain; +@property(copy, readonly) NSString *PEMCertChain; /** * Select the transport type to be used for this call. @@ -278,17 +278,17 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default * root certificates. */ -@property(copy, readwrite) NSString *pemRootCert; +@property(copy, readwrite) NSString *PEMRootCertificates; /** * PEM format private key for client authentication, if required by the server. */ -@property(copy, readwrite) NSString *pemPrivateKey; +@property(copy, readwrite) NSString *PEMPrivateKey; /** * PEM format certificate chain for client authentication, if required by the server. */ -@property(copy, readwrite) NSString *pemCertChain; +@property(copy, readwrite) NSString *PEMCertChain; /** * Select the transport type to be used for this call. diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 1f25df7d53..539cb9929d 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -32,9 +32,9 @@ static const NSTimeInterval kDefaultConnectMinTimeout = 0; static const NSTimeInterval kDefaultConnectInitialBackoff = 0; static const NSTimeInterval kDefaultConnectMaxBackoff = 0; static NSDictionary *const kDefaultAdditionalChannelArgs = nil; -static NSString *const kDefaultPemRootCert = nil; -static NSString *const kDefaultPemPrivateKey = nil; -static NSString *const kDefaultPemCertChain = nil; +static NSString *const kDefaultPEMRootCertificates = nil; +static NSString *const kDefaultPEMPrivateKey = nil; +static NSString *const kDefaultPEMCertChain = nil; static NSString *const kDefaultOauth2AccessToken = nil; static const id kDefaultAuthTokenProvider = nil; static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2BoringSSL; @@ -60,9 +60,9 @@ static NSUInteger kDefaultChannelId = 0; NSTimeInterval _connectInitialBackoff; NSTimeInterval _connectMaxBackoff; NSDictionary *_additionalChannelArgs; - NSString *_pemRootCert; - NSString *_pemPrivateKey; - NSString *_pemCertChain; + NSString *_PEMRootCertificates; + NSString *_PEMPrivateKey; + NSString *_PEMCertChain; GRPCTransportType _transportType; NSString *_hostNameOverride; id _logContext; @@ -85,9 +85,9 @@ static NSUInteger kDefaultChannelId = 0; @synthesize connectInitialBackoff = _connectInitialBackoff; @synthesize connectMaxBackoff = _connectMaxBackoff; @synthesize additionalChannelArgs = _additionalChannelArgs; -@synthesize pemRootCert = _pemRootCert; -@synthesize pemPrivateKey = _pemPrivateKey; -@synthesize pemCertChain = _pemCertChain; +@synthesize PEMRootCertificates = _PEMRootCertificates; +@synthesize PEMPrivateKey = _PEMPrivateKey; +@synthesize PEMCertChain = _PEMCertChain; @synthesize transportType = _transportType; @synthesize hostNameOverride = _hostNameOverride; @synthesize logContext = _logContext; @@ -110,9 +110,9 @@ static NSUInteger kDefaultChannelId = 0; connectInitialBackoff:kDefaultConnectInitialBackoff connectMaxBackoff:kDefaultConnectMaxBackoff additionalChannelArgs:kDefaultAdditionalChannelArgs - pemRootCert:kDefaultPemRootCert - pemPrivateKey:kDefaultPemPrivateKey - pemCertChain:kDefaultPemCertChain + PEMRootCertificates:kDefaultPEMRootCertificates + PEMPrivateKey:kDefaultPEMPrivateKey + PEMCertChain:kDefaultPEMCertChain transportType:kDefaultTransportType hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext @@ -135,9 +135,9 @@ static NSUInteger kDefaultChannelId = 0; connectInitialBackoff:(NSTimeInterval)connectInitialBackoff connectMaxBackoff:(NSTimeInterval)connectMaxBackoff additionalChannelArgs:(NSDictionary *)additionalChannelArgs - pemRootCert:(NSString *)pemRootCert - pemPrivateKey:(NSString *)pemPrivateKey - pemCertChain:(NSString *)pemCertChain + PEMRootCertificates:(NSString *)PEMRootCertificates + PEMPrivateKey:(NSString *)PEMPrivateKey + PEMCertChain:(NSString *)PEMCertChain transportType:(GRPCTransportType)transportType hostNameOverride:(NSString *)hostNameOverride logContext:(id)logContext @@ -159,9 +159,9 @@ static NSUInteger kDefaultChannelId = 0; _connectInitialBackoff = connectInitialBackoff; _connectMaxBackoff = connectMaxBackoff; _additionalChannelArgs = additionalChannelArgs; - _pemRootCert = pemRootCert; - _pemPrivateKey = pemPrivateKey; - _pemCertChain = pemCertChain; + _PEMRootCertificates = PEMRootCertificates; + _PEMPrivateKey = PEMPrivateKey; + _PEMCertChain = PEMCertChain; _transportType = transportType; _hostNameOverride = hostNameOverride; _logContext = logContext; @@ -188,9 +188,9 @@ static NSUInteger kDefaultChannelId = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:[_additionalChannelArgs copy] - pemRootCert:_pemRootCert - pemPrivateKey:_pemPrivateKey - pemCertChain:_pemCertChain + PEMRootCertificates:_PEMRootCertificates + PEMPrivateKey:_PEMPrivateKey + PEMCertChain:_PEMCertChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -216,9 +216,9 @@ static NSUInteger kDefaultChannelId = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:[_additionalChannelArgs copy] - pemRootCert:_pemRootCert - pemPrivateKey:_pemPrivateKey - pemCertChain:_pemCertChain + PEMRootCertificates:_PEMRootCertificates + PEMPrivateKey:_PEMPrivateKey + PEMCertChain:_PEMCertChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -246,9 +246,9 @@ static NSUInteger kDefaultChannelId = 0; @dynamic connectInitialBackoff; @dynamic connectMaxBackoff; @dynamic additionalChannelArgs; -@dynamic pemRootCert; -@dynamic pemPrivateKey; -@dynamic pemCertChain; +@dynamic PEMRootCertificates; +@dynamic PEMPrivateKey; +@dynamic PEMCertChain; @dynamic transportType; @dynamic hostNameOverride; @dynamic logContext; @@ -271,9 +271,9 @@ static NSUInteger kDefaultChannelId = 0; connectInitialBackoff:kDefaultConnectInitialBackoff connectMaxBackoff:kDefaultConnectMaxBackoff additionalChannelArgs:kDefaultAdditionalChannelArgs - pemRootCert:kDefaultPemRootCert - pemPrivateKey:kDefaultPemPrivateKey - pemCertChain:kDefaultPemCertChain + PEMRootCertificates:kDefaultPEMRootCertificates + PEMPrivateKey:kDefaultPEMPrivateKey + PEMCertChain:kDefaultPEMCertChain transportType:kDefaultTransportType hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext @@ -298,9 +298,9 @@ static NSUInteger kDefaultChannelId = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:[_additionalChannelArgs copy] - pemRootCert:_pemRootCert - pemPrivateKey:_pemPrivateKey - pemCertChain:_pemCertChain + PEMRootCertificates:_PEMRootCertificates + PEMPrivateKey:_PEMPrivateKey + PEMCertChain:_PEMCertChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -326,9 +326,9 @@ static NSUInteger kDefaultChannelId = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:[_additionalChannelArgs copy] - pemRootCert:_pemRootCert - pemPrivateKey:_pemPrivateKey - pemCertChain:_pemCertChain + PEMRootCertificates:_PEMRootCertificates + PEMPrivateKey:_PEMPrivateKey + PEMCertChain:_PEMCertChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -421,16 +421,16 @@ static NSUInteger kDefaultChannelId = 0; _additionalChannelArgs = additionalChannelArgs; } -- (void)setPemRootCert:(NSString *)pemRootCert { - _pemRootCert = pemRootCert; +- (void)setPEMRootCertificates:(NSString *)PEMRootCertificates { + _PEMRootCertificates = PEMRootCertificates; } -- (void)setPemPrivateKey:(NSString *)pemPrivateKey { - _pemPrivateKey = pemPrivateKey; +- (void)setPEMPrivateKey:(NSString *)PEMPrivateKey { + _PEMPrivateKey = PEMPrivateKey; } -- (void)setPemCertChain:(NSString *)pemCertChain { - _pemCertChain = pemCertChain; +- (void)setPEMCertChain:(NSString *)PEMCertChain { + _PEMCertChain = PEMCertChain; } - (void)setTransportType:(GRPCTransportType)transportType { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 2b08eb8d5e..9007f5fed5 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -54,9 +54,9 @@ const NSTimeInterval kChannelDestroyDelay = 30; #ifdef GRPC_COMPILE_WITH_CRONET if (![GRPCCall isUsingCronet]) { #endif - factory = [GRPCSecureChannelFactory factoryWithPEMRootCerts:_callOptions.pemRootCert - privateKey:_callOptions.pemPrivateKey - certChain:_callOptions.pemCertChain + factory = [GRPCSecureChannelFactory factoryWithPEMRootCerts:_callOptions.PEMRootCertificates + privateKey:_callOptions.PEMPrivateKey + certChain:_callOptions.PEMCertChain error:&error]; if (error) { NSLog(@"Error creating secure channel factory: %@", error); @@ -167,14 +167,14 @@ const NSTimeInterval kChannelDestroyDelay = 30; [obj.callOptions.additionalChannelArgs isEqualToDictionary:_callOptions.additionalChannelArgs])) return NO; - if (!(obj.callOptions.pemRootCert == _callOptions.pemRootCert || - [obj.callOptions.pemRootCert isEqualToString:_callOptions.pemRootCert])) + if (!(obj.callOptions.PEMRootCertificates == _callOptions.PEMRootCertificates || + [obj.callOptions.PEMRootCertificates isEqualToString:_callOptions.PEMRootCertificates])) return NO; - if (!(obj.callOptions.pemPrivateKey == _callOptions.pemPrivateKey || - [obj.callOptions.pemPrivateKey isEqualToString:_callOptions.pemPrivateKey])) + if (!(obj.callOptions.PEMPrivateKey == _callOptions.PEMPrivateKey || + [obj.callOptions.PEMPrivateKey isEqualToString:_callOptions.PEMPrivateKey])) return NO; - if (!(obj.callOptions.pemCertChain == _callOptions.pemCertChain || - [obj.callOptions.pemCertChain isEqualToString:_callOptions.pemCertChain])) + if (!(obj.callOptions.PEMCertChain == _callOptions.PEMCertChain || + [obj.callOptions.PEMCertChain isEqualToString:_callOptions.PEMCertChain])) return NO; if (!(obj.callOptions.hostNameOverride == _callOptions.hostNameOverride || [obj.callOptions.hostNameOverride isEqualToString:_callOptions.hostNameOverride])) @@ -204,9 +204,9 @@ const NSTimeInterval kChannelDestroyDelay = 30; result ^= (unsigned int)(_callOptions.connectInitialBackoff * 1000); result ^= (unsigned int)(_callOptions.connectMaxBackoff * 1000); result ^= _callOptions.additionalChannelArgs.hash; - result ^= _callOptions.pemRootCert.hash; - result ^= _callOptions.pemPrivateKey.hash; - result ^= _callOptions.pemCertChain.hash; + result ^= _callOptions.PEMRootCertificates.hash; + result ^= _callOptions.PEMPrivateKey.hash; + result ^= _callOptions.PEMCertChain.hash; result ^= _callOptions.hostNameOverride.hash; result ^= _callOptions.transportType; result ^= [_callOptions.logContext hash]; diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 0e3fa610f9..429958b408 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -38,8 +38,8 @@ NS_ASSUME_NONNULL_BEGIN static NSMutableDictionary *kHostCache; @implementation GRPCHost { - NSString *_pemRootCerts; - NSString *_pemPrivateKey; + NSString *_PEMRootCertificates; + NSString *_PEMPrivateKey; NSString *_pemCertChain; } @@ -92,8 +92,8 @@ static NSMutableDictionary *kHostCache; withPrivateKey:(nullable NSString *)pemPrivateKey withCertChain:(nullable NSString *)pemCertChain error:(NSError **)errorPtr { - _pemRootCerts = pemRootCerts; - _pemPrivateKey = pemPrivateKey; + _PEMRootCertificates = pemRootCerts; + _PEMPrivateKey = pemPrivateKey; _pemCertChain = pemCertChain; return YES; } @@ -109,9 +109,9 @@ static NSMutableDictionary *kHostCache; options.connectMinTimeout = (NSTimeInterval)_minConnectTimeout / 1000; options.connectInitialBackoff = (NSTimeInterval)_initialConnectBackoff / 1000; options.connectMaxBackoff = (NSTimeInterval)_maxConnectBackoff / 1000; - options.pemRootCert = _pemRootCerts; - options.pemPrivateKey = _pemPrivateKey; - options.pemCertChain = _pemCertChain; + options.PEMRootCertificates = _PEMRootCertificates; + options.PEMPrivateKey = _PEMPrivateKey; + options.PEMCertChain = _pemCertChain; options.hostNameOverride = _hostNameOverride; options.transportType = _transportType; options.logContext = _logContext; diff --git a/src/objective-c/tests/InteropTests.h b/src/objective-c/tests/InteropTests.h index e223839d3a..038f24b62e 100644 --- a/src/objective-c/tests/InteropTests.h +++ b/src/objective-c/tests/InteropTests.h @@ -51,7 +51,7 @@ * The root certificates to be used. The base implementation returns nil. Subclasses should override * to appropriate settings. */ -+ (NSString *)pemRootCert; ++ (NSString *)PEMRootCertificates; /** * The root certificates to be used. The base implementation returns nil. Subclasses should override diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 16d5040a73..0835ff909f 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -147,7 +147,7 @@ BOOL isRemoteInteropTest(NSString *host) { return GRPCTransportTypeChttp2BoringSSL; } -+ (NSString *)pemRootCert { ++ (NSString *)PEMRootCertificates { return nil; } @@ -202,7 +202,7 @@ BOOL isRemoteInteropTest(NSString *host) { GPBEmpty *request = [GPBEmpty message]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.transportType = self.class.transportType; - options.pemRootCert = self.class.pemRootCert; + options.PEMRootCertificates = self.class.PEMRootCertificates; options.hostNameOverride = self.class.hostNameOverride; [_service @@ -484,7 +484,7 @@ BOOL isRemoteInteropTest(NSString *host) { requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.transportType = self.class.transportType; - options.pemRootCert = self.class.pemRootCert; + options.PEMRootCertificates = self.class.PEMRootCertificates; options.hostNameOverride = self.class.hostNameOverride; __block GRPCStreamingProtoCall *call = [_service @@ -629,7 +629,7 @@ BOOL isRemoteInteropTest(NSString *host) { GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.transportType = self.class.transportType; - options.pemRootCert = self.class.pemRootCert; + options.PEMRootCertificates = self.class.PEMRootCertificates; options.hostNameOverride = self.class.hostNameOverride; id request = diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m index 42e327a330..a9c6918333 100644 --- a/src/objective-c/tests/InteropTestsLocalCleartext.m +++ b/src/objective-c/tests/InteropTestsLocalCleartext.m @@ -41,7 +41,7 @@ static int32_t kLocalInteropServerOverhead = 10; return kLocalCleartextHost; } -+ (NSString *)pemRootCert { ++ (NSString *)PEMRootCertificates { return nil; } diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m index 997dd87eee..759a080380 100644 --- a/src/objective-c/tests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTestsLocalSSL.m @@ -40,7 +40,7 @@ static int32_t kLocalInteropServerOverhead = 10; return kLocalSSLHost; } -+ (NSString *)pemRootCert { ++ (NSString *)PEMRootCertificates { NSBundle *bundle = [NSBundle bundleForClass:self.class]; NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"]; diff --git a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m index b1d663584c..237804d23d 100644 --- a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m +++ b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m @@ -115,7 +115,7 @@ dispatch_once_t initCronet; options = [[GRPCCallOptions alloc] init]; options.transportType = GRPCTransportTypeChttp2BoringSSL; - options.pemRootCert = certs; + options.PEMRootCertificates = certs; options.hostNameOverride = @"foo.test.google.fr"; _localSSLService.options = options; } diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m index 30670facad..c1cd9b81ef 100644 --- a/src/objective-c/tests/InteropTestsRemote.m +++ b/src/objective-c/tests/InteropTestsRemote.m @@ -41,7 +41,7 @@ static int32_t kRemoteInteropServerOverhead = 12; return kRemoteSSLHost; } -+ (NSString *)pemRootCert { ++ (NSString *)PEMRootCertificates { return nil; } -- cgit v1.2.3 From 521ffacd7c6b90b884aae72bc342d134e41053fb Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 14:44:55 -0700 Subject: Add example to channelPoolDomain --- src/objective-c/GRPCClient/GRPCCallOptions.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index ea7c1bf22d..dcd4de6223 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -307,7 +307,9 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * A string that specify the domain where channel is being cached. Channels with different domains - * will not get cached to the same connection. + * will not get cached to the same connection. For example, a gRPC example app may use the channel + * pool domain 'io.grpc.example' so that its calls do not reuse the channel created by other modules + * in the same process. */ @property(copy, readwrite) NSString *channelPoolDomain; -- cgit v1.2.3 From 2c47c953380d0a02df4bc7e4d7772b235cd7da9c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 16:17:03 -0700 Subject: Rename channelId->channelID --- src/objective-c/GRPCClient/GRPCCallOptions.h | 14 +++++------ src/objective-c/GRPCClient/GRPCCallOptions.m | 28 +++++++++++----------- .../GRPCClient/private/GRPCChannelPool.m | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index dcd4de6223..9c6e00fd18 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -181,9 +181,9 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * Channel id allows a call to force creating a new channel (connection) rather than using a cached - * channel. Calls using distinct channelId will not get cached to the same connection. + * channel. Calls using distinct channelID will not get cached to the same connection. */ -@property(readonly) NSUInteger channelId; +@property(readonly) NSUInteger channelID; @end @@ -307,16 +307,16 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * A string that specify the domain where channel is being cached. Channels with different domains - * will not get cached to the same connection. For example, a gRPC example app may use the channel - * pool domain 'io.grpc.example' so that its calls do not reuse the channel created by other modules - * in the same process. + * will not get cached to the same channel. For example, a gRPC example app may use the channel pool + * domain 'io.grpc.example' so that its calls do not reuse the channel created by other modules in + * the same process. */ @property(copy, readwrite) NSString *channelPoolDomain; /** * Channel id allows a call to force creating a new channel (connection) rather than using a cached - * channel. Calls using distinct channelId will not get cached to the same connection. + * channel. Calls using distinct channelID's will not get cached to the same channel. */ -@property(readwrite) NSUInteger channelId; +@property(readwrite) NSUInteger channelID; @end diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 539cb9929d..ad90fb829e 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -41,7 +41,7 @@ static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2Bo static NSString *const kDefaultHostNameOverride = nil; static const id kDefaultLogContext = nil; static NSString *kDefaultChannelPoolDomain = nil; -static NSUInteger kDefaultChannelId = 0; +static NSUInteger kDefaultChannelID = 0; @implementation GRPCCallOptions { @protected @@ -67,7 +67,7 @@ static NSUInteger kDefaultChannelId = 0; NSString *_hostNameOverride; id _logContext; NSString *_channelPoolDomain; - NSUInteger _channelId; + NSUInteger _channelID; } @synthesize serverAuthority = _serverAuthority; @@ -92,7 +92,7 @@ static NSUInteger kDefaultChannelId = 0; @synthesize hostNameOverride = _hostNameOverride; @synthesize logContext = _logContext; @synthesize channelPoolDomain = _channelPoolDomain; -@synthesize channelId = _channelId; +@synthesize channelID = _channelID; - (instancetype)init { return [self initWithServerAuthority:kDefaultServerAuthority @@ -117,7 +117,7 @@ static NSUInteger kDefaultChannelId = 0; hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext channelPoolDomain:kDefaultChannelPoolDomain - channelId:kDefaultChannelId]; + channelID:kDefaultChannelID]; } - (instancetype)initWithServerAuthority:(NSString *)serverAuthority @@ -142,7 +142,7 @@ static NSUInteger kDefaultChannelId = 0; hostNameOverride:(NSString *)hostNameOverride logContext:(id)logContext channelPoolDomain:(NSString *)channelPoolDomain - channelId:(NSUInteger)channelId { + channelID:(NSUInteger)channelID { if ((self = [super init])) { _serverAuthority = serverAuthority; _timeout = timeout; @@ -166,7 +166,7 @@ static NSUInteger kDefaultChannelId = 0; _hostNameOverride = hostNameOverride; _logContext = logContext; _channelPoolDomain = channelPoolDomain; - _channelId = channelId; + _channelID = channelID; } return self; } @@ -195,7 +195,7 @@ static NSUInteger kDefaultChannelId = 0; hostNameOverride:_hostNameOverride logContext:_logContext channelPoolDomain:_channelPoolDomain - channelId:_channelId]; + channelID:_channelID]; return newOptions; } @@ -223,7 +223,7 @@ static NSUInteger kDefaultChannelId = 0; hostNameOverride:_hostNameOverride logContext:_logContext channelPoolDomain:_channelPoolDomain - channelId:_channelId]; + channelID:_channelID]; return newOptions; } @@ -253,7 +253,7 @@ static NSUInteger kDefaultChannelId = 0; @dynamic hostNameOverride; @dynamic logContext; @dynamic channelPoolDomain; -@dynamic channelId; +@dynamic channelID; - (instancetype)init { return [self initWithServerAuthority:kDefaultServerAuthority @@ -278,7 +278,7 @@ static NSUInteger kDefaultChannelId = 0; hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext channelPoolDomain:kDefaultChannelPoolDomain - channelId:kDefaultChannelId]; + channelID:kDefaultChannelID]; } - (nonnull id)copyWithZone:(NSZone *)zone { @@ -305,7 +305,7 @@ static NSUInteger kDefaultChannelId = 0; hostNameOverride:_hostNameOverride logContext:_logContext channelPoolDomain:_channelPoolDomain - channelId:_channelId]; + channelID:_channelID]; return newOptions; } @@ -333,7 +333,7 @@ static NSUInteger kDefaultChannelId = 0; hostNameOverride:_hostNameOverride logContext:_logContext channelPoolDomain:_channelPoolDomain - channelId:_channelId]; + channelID:_channelID]; return newOptions; } @@ -449,8 +449,8 @@ static NSUInteger kDefaultChannelId = 0; _channelPoolDomain = channelPoolDomain; } -- (void)setChannelId:(NSUInteger)channelId { - _channelId = channelId; +- (void)setChannelID:(NSUInteger)channelID { + _channelID = channelID; } @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 9007f5fed5..37e42f8c75 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -186,7 +186,7 @@ const NSTimeInterval kChannelDestroyDelay = 30; if (!(obj.callOptions.channelPoolDomain == _callOptions.channelPoolDomain || [obj.callOptions.channelPoolDomain isEqualToString:_callOptions.channelPoolDomain])) return NO; - if (!(obj.callOptions.channelId == _callOptions.channelId)) return NO; + if (!(obj.callOptions.channelID == _callOptions.channelID)) return NO; return YES; } @@ -211,7 +211,7 @@ const NSTimeInterval kChannelDestroyDelay = 30; result ^= _callOptions.transportType; result ^= [_callOptions.logContext hash]; result ^= _callOptions.channelPoolDomain.hash; - result ^= _callOptions.channelId; + result ^= _callOptions.channelID; return result; } -- cgit v1.2.3 From 229651a371ac590f47793cdacc8d28c0ac74bf48 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 16:17:38 -0700 Subject: Check range of value-typed channel arg --- src/objective-c/GRPCClient/private/ChannelArgsUtil.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m index 8ebf3a2659..04a5cc8345 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -21,6 +21,8 @@ #include #include +#include + static void *copy_pointer_arg(void *p) { // Add ref count to the object when making copy id obj = (__bridge id)p; @@ -79,6 +81,11 @@ grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) { arg->type = GRPC_ARG_STRING; arg->value.string = gpr_strdup([value UTF8String]); } else if ([value respondsToSelector:@selector(intValue)]) { + if ([value compare:[NSNumber numberWithInteger:INT_MAX]] == NSOrderedDescending || + [value compare:[NSNumber numberWithInteger:INT_MIN]] == NSOrderedAscending) { + [NSException raise:NSInvalidArgumentException + format:@"Range exceeded for a value typed channel argument: %@", value]; + } arg->type = GRPC_ARG_INTEGER; arg->value.integer = [value intValue]; } else if (value != nil) { -- cgit v1.2.3 From ecf85f045975265d19a94b116e94f7fea42a9d38 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 16:23:25 -0700 Subject: Copy fields in GRPCCallOptions initializer --- src/objective-c/GRPCClient/GRPCCallOptions.m | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index ad90fb829e..f9706b1846 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -144,12 +144,12 @@ static NSUInteger kDefaultChannelID = 0; channelPoolDomain:(NSString *)channelPoolDomain channelID:(NSUInteger)channelID { if ((self = [super init])) { - _serverAuthority = serverAuthority; + _serverAuthority = [serverAuthority copy]; _timeout = timeout; - _oauth2AccessToken = oauth2AccessToken; + _oauth2AccessToken = [oauth2AccessToken copy]; _authTokenProvider = authTokenProvider; - _initialMetadata = initialMetadata; - _userAgentPrefix = userAgentPrefix; + _initialMetadata = [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES]; + _userAgentPrefix = [userAgentPrefix copy]; _responseSizeLimit = responseSizeLimit; _compressAlgorithm = compressAlgorithm; _enableRetry = enableRetry; @@ -158,14 +158,14 @@ static NSUInteger kDefaultChannelID = 0; _connectMinTimeout = connectMinTimeout; _connectInitialBackoff = connectInitialBackoff; _connectMaxBackoff = connectMaxBackoff; - _additionalChannelArgs = additionalChannelArgs; - _PEMRootCertificates = PEMRootCertificates; - _PEMPrivateKey = PEMPrivateKey; - _PEMCertChain = PEMCertChain; + _additionalChannelArgs = [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; + _PEMRootCertificates = [PEMRootCertificates copy]; + _PEMPrivateKey = [PEMPrivateKey copy]; + _PEMCertChain = [PEMCertChain copy]; _transportType = transportType; - _hostNameOverride = hostNameOverride; + _hostNameOverride = [hostNameOverride copy]; _logContext = logContext; - _channelPoolDomain = channelPoolDomain; + _channelPoolDomain = [channelPoolDomain copy]; _channelID = channelID; } return self; -- cgit v1.2.3 From 1c8751f366fc4b51a49cc83aa8477dd2b12664a8 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 16:33:02 -0700 Subject: Avoid copy in GRPCCallOptions:copyWithZone: --- src/objective-c/GRPCClient/GRPCCallOptions.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index f9706b1846..c700bba794 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -187,7 +187,7 @@ static NSUInteger kDefaultChannelID = 0; connectMinTimeout:_connectMinTimeout connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff - additionalChannelArgs:[_additionalChannelArgs copy] + additionalChannelArgs:_additionalChannelArgs PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey PEMCertChain:_PEMCertChain -- cgit v1.2.3 From 454966e36cab39ee1b18828575a23c75d812d895 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 16:38:14 -0700 Subject: Copy in GRPCCallOptions setters --- src/objective-c/GRPCClient/GRPCCallOptions.m | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index c700bba794..b19917d778 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -338,7 +338,7 @@ static NSUInteger kDefaultChannelID = 0; } - (void)setServerAuthority:(NSString *)serverAuthority { - _serverAuthority = serverAuthority; + _serverAuthority = [serverAuthority copy]; } - (void)setTimeout:(NSTimeInterval)timeout { @@ -350,7 +350,7 @@ static NSUInteger kDefaultChannelID = 0; } - (void)setOauth2AccessToken:(NSString *)oauth2AccessToken { - _oauth2AccessToken = oauth2AccessToken; + _oauth2AccessToken = [oauth2AccessToken copy]; } - (void)setAuthTokenProvider:(id)authTokenProvider { @@ -358,11 +358,11 @@ static NSUInteger kDefaultChannelID = 0; } - (void)setInitialMetadata:(NSDictionary *)initialMetadata { - _initialMetadata = initialMetadata; + _initialMetadata = [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES]; } - (void)setUserAgentPrefix:(NSString *)userAgentPrefix { - _userAgentPrefix = userAgentPrefix; + _userAgentPrefix = [userAgentPrefix copy]; } - (void)setResponseSizeLimit:(NSUInteger)responseSizeLimit { @@ -418,19 +418,19 @@ static NSUInteger kDefaultChannelID = 0; } - (void)setAdditionalChannelArgs:(NSDictionary *)additionalChannelArgs { - _additionalChannelArgs = additionalChannelArgs; + _additionalChannelArgs = [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; } - (void)setPEMRootCertificates:(NSString *)PEMRootCertificates { - _PEMRootCertificates = PEMRootCertificates; + _PEMRootCertificates = [PEMRootCertificates copy]; } - (void)setPEMPrivateKey:(NSString *)PEMPrivateKey { - _PEMPrivateKey = PEMPrivateKey; + _PEMPrivateKey = [PEMPrivateKey copy]; } - (void)setPEMCertChain:(NSString *)PEMCertChain { - _PEMCertChain = PEMCertChain; + _PEMCertChain = [PEMCertChain copy]; } - (void)setTransportType:(GRPCTransportType)transportType { @@ -438,7 +438,7 @@ static NSUInteger kDefaultChannelID = 0; } - (void)setHostNameOverride:(NSString *)hostNameOverride { - _hostNameOverride = hostNameOverride; + _hostNameOverride = [hostNameOverride copy]; } - (void)setLogContext:(id)logContext { @@ -446,7 +446,7 @@ static NSUInteger kDefaultChannelID = 0; } - (void)setChannelPoolDomain:(NSString *)channelPoolDomain { - _channelPoolDomain = channelPoolDomain; + _channelPoolDomain = [channelPoolDomain copy]; } - (void)setChannelID:(NSUInteger)channelID { -- cgit v1.2.3 From 92d6e285d174bf6c8b2e60054f82d7288231da14 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 11 Oct 2018 16:42:53 -0700 Subject: Polish exception message --- src/objective-c/GRPCClient/private/ChannelArgsUtil.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m index 04a5cc8345..b26fb12d59 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -84,7 +84,7 @@ grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) { if ([value compare:[NSNumber numberWithInteger:INT_MAX]] == NSOrderedDescending || [value compare:[NSNumber numberWithInteger:INT_MIN]] == NSOrderedAscending) { [NSException raise:NSInvalidArgumentException - format:@"Range exceeded for a value typed channel argument: %@", value]; + format:@"Out of range for a value-typed channel argument: %@", value]; } arg->type = GRPC_ARG_INTEGER; arg->value.integer = [value intValue]; @@ -94,7 +94,7 @@ grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) { arg->value.pointer.vtable = &objc_arg_vtable; } else { [NSException raise:NSInvalidArgumentException - format:@"Invalid value type: %@", [value class]]; + format:@"Invalid channel argument type: %@", [value class]]; } } -- cgit v1.2.3 From e457b0dacc70a28fffd42064236fbf240952e3b4 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 12 Oct 2018 09:02:52 -0700 Subject: Fix missing initialMetadata in GRPCMutableCallOptions --- src/objective-c/GRPCClient/GRPCCallOptions.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 9c6e00fd18..68d3eb4fbb 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -223,6 +223,11 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { */ @property(readwrite) id authTokenProvider; +/** + * Initial metadata key-value pairs that should be included in the request. + */ +@property(copy, readonly) NSDictionary *initialMetadata; + // Channel parameters; take into account of channel signature. /** -- cgit v1.2.3 From e69a7cc7f7497e67232843a3843f543740480c4e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 12 Oct 2018 11:21:52 -0700 Subject: patch the previous fix --- src/objective-c/GRPCClient/GRPCCallOptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 68d3eb4fbb..ff575d09cf 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -226,7 +226,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * Initial metadata key-value pairs that should be included in the request. */ -@property(copy, readonly) NSDictionary *initialMetadata; +@property(copy, readwrite) NSDictionary *initialMetadata; // Channel parameters; take into account of channel signature. -- cgit v1.2.3 From bf092064962664a1a949750c9f9b273f7d27c529 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 15:34:39 -0700 Subject: Separate GRPCProtoResponseHandler from GRPCResponseHandler --- src/objective-c/GRPCClient/GRPCCall.h | 6 +-- src/objective-c/GRPCClient/GRPCCall.m | 4 +- src/objective-c/ProtoRPC/ProtoRPC.h | 37 +++++++++++++++- src/objective-c/ProtoRPC/ProtoRPC.m | 76 ++++++++++++++++++--------------- src/objective-c/tests/GRPCClientTests.m | 2 +- src/objective-c/tests/InteropTests.m | 4 +- 6 files changed, 85 insertions(+), 44 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 304fb17cca..48f4514a06 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -157,10 +157,10 @@ extern id const kGRPCTrailersKey; - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; /** - * Issued when a message is received from the server. The message may be raw data from the server - * (when using \a GRPCCall2 directly) or deserialized proto object (when using \a ProtoRPC). + * Issued when a message is received from the server. The message is the raw data received from the + * server, with decompression and without proto deserialization. */ -- (void)receivedMessage:(id)message; +- (void)receivedRawMessage:(id)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 36cb71399c..eb9b21eccb 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -236,9 +236,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)issueMessage:(id)message { id handler = self->_handler; - if ([handler respondsToSelector:@selector(receivedMessage:)]) { + if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { dispatch_async(handler.dispatchQueue, ^{ - [handler receivedMessage:message]; + [handler receivedRawMessage:message]; }); } } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index a045ef10a6..d20098ce8c 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -23,6 +23,39 @@ @class GPBMessage; +/** An object can implement this protocol to receive responses from server from a call. */ +@protocol GRPCProtoResponseHandler + +@optional + +/** Issued when initial metadata is received from the server. */ +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; + +/** + * Issued when a message is received from the server. The message is the deserialized proto object. + */ +- (void)receivedProtoMessage:(id)message; + +/** + * Issued when a call finished. If the call finished successfully, \a error is nil and \a + * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error + * is non-nil and contains the corresponding error information, including gRPC error codes and + * error descriptions. + */ +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error; + +@required + +/** + * All the responses must be issued to a user-provided dispatch queue. This property specifies the + * dispatch queue to be used for issuing the notifications. A serial queue should be provided if + * the order of responses (initial metadata, message, message, ..., message, trailing metadata) + * needs to be maintained. + */ +@property(atomic, readonly) dispatch_queue_t dispatchQueue; + +@end + /** A unary-request RPC call with Protobuf. */ @interface GRPCUnaryProtoCall : NSObject @@ -36,7 +69,7 @@ */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; @@ -57,7 +90,7 @@ * returned to users by methods of the generated service. */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 957d636534..7a57affbf1 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -33,7 +33,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { if ((self = [super init])) { @@ -60,7 +60,7 @@ @implementation GRPCStreamingProtoCall { GRPCRequestOptions *_requestOptions; - id _handler; + id _handler; GRPCCallOptions *_callOptions; Class _responseClass; @@ -69,7 +69,7 @@ } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { if ((self = [super init])) { @@ -98,16 +98,18 @@ _call = nil; } if (_handler) { - id handler = _handler; - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; - }); + id handler = _handler; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + }); + } _handler = nil; } }); @@ -136,27 +138,33 @@ - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { if (_handler) { - id handler = _handler; - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:initialMetadata]; - }); + id handler = _handler; + if ([handler respondsToSelector:@selector(initialMetadata:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedInitialMetadata:initialMetadata]; + }); + } } } -- (void)receivedMessage:(NSData *)message { +- (void)receivedRawMessage:(NSData *)message { if (_handler) { - id handler = _handler; + id handler = _handler; NSError *error = nil; id parsed = [_responseClass parseFromData:message error:&error]; if (parsed) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedMessage:parsed]; - }); + if ([handler respondsToSelector:@selector(receivedProtoMessage:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedProtoMessage:parsed]; + }); + } } else { - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:nil error:error]; - }); - handler = nil; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:nil error:error]; + }); + } + _handler = nil; [_call cancel]; _call = nil; } @@ -165,16 +173,16 @@ - (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { if (_handler) { - id handler = _handler; - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:trailingMetadata error:error]; - }); + id handler = _handler; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:trailingMetadata error:error]; + }); + } _handler = nil; } - if (_call) { - [_call cancel]; - _call = nil; - } + [_call cancel]; + _call = nil; } - (dispatch_queue_t)dispatchQueue { diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 8a4eddb1b7..f961b6a86f 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -120,7 +120,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } } -- (void)receivedMessage:(id)message { +- (void)receivedProtoMessage:(id)message { if (_messageCallback) { _messageCallback(message); } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 0835ff909f..11d4b95663 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -75,7 +75,7 @@ BOOL isRemoteInteropTest(NSString *host) { } // Convenience class to use blocks as callbacks -@interface InteropTestsBlockCallbacks : NSObject +@interface InteropTestsBlockCallbacks : NSObject - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback messageCallback:(void (^)(id))messageCallback @@ -108,7 +108,7 @@ BOOL isRemoteInteropTest(NSString *host) { } } -- (void)receivedMessage:(id)message { +- (void)receivedProtoMessage:(id)message { if (_messageCallback) { _messageCallback(message); } -- cgit v1.2.3 From 9f47e76fc8b72c432e9b3d4711c7b2898236f37b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 16:06:54 -0700 Subject: QoS for internal dispatch queues --- src/objective-c/GRPCClient/GRPCCall.m | 11 ++++++++--- src/objective-c/ProtoRPC/ProtoRPC.m | 6 +++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index eb9b21eccb..df50d43e07 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -108,7 +108,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; _handler = responseHandler; _initialMetadataPublished = NO; _pipe = [GRXBufferedPipe pipe]; - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + if (@available(iOS 8.0, *)) { + _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + } else { + // Fallback on earlier versions + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } _started = NO; } @@ -226,7 +231,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { - id handler = self->_handler; + id handler = _handler; if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { dispatch_async(handler.dispatchQueue, ^{ [handler receivedInitialMetadata:initialMetadata]; @@ -235,7 +240,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueMessage:(id)message { - id handler = self->_handler; + id handler = _handler; if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { dispatch_async(handler.dispatchQueue, ^{ [handler receivedRawMessage:message]; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 7a57affbf1..b860515d4e 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -77,7 +77,11 @@ _handler = handler; _callOptions = [callOptions copy]; _responseClass = responseClass; - _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + if (@available(iOS 8.0, *)) { + _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + } else { + _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + } [self start]; } -- cgit v1.2.3 From b3d236d1bf4acebce821fb7f36c262e34104a9b1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 16:07:35 -0700 Subject: Prevent empty string --- src/objective-c/GRPCClient/GRPCCall.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index df50d43e07..7b100cb02a 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -380,8 +380,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; callSafety:(GRPCCallSafety)safety requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { - if (!host || !path) { - [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; + if (host.length == 0 || path.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil or empty."]; } if (requestWriter.state != GRXWriterStateNotStarted) { [NSException raise:NSInvalidArgumentException -- cgit v1.2.3 From da43545ff7b4b1a6e310ff7fdeec6eb21f0e26b8 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 16:38:04 -0700 Subject: Check callSafety in -init in GRPCCall --- src/objective-c/GRPCClient/GRPCCall.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 7b100cb02a..50c38ed99e 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -383,6 +383,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (host.length == 0 || path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil or empty."]; } + if (safety > GRPCCallSafetyCacheableRequest) { + [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; + } if (requestWriter.state != GRXWriterStateNotStarted) { [NSException raise:NSInvalidArgumentException format:@"The requests writer can't be already started."]; @@ -556,8 +559,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; case GRPCCallSafetyCacheableRequest: callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; break; - default: - [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; } uint32_t callFlag = callSafetyFlags; -- cgit v1.2.3 From 7d32a2cb25275e03a44184ad9f8a3e494e62dd0d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 17:10:32 -0700 Subject: Set user's dispatch queue's handler to internal serial queue --- src/objective-c/GRPCClient/GRPCCall.h | 4 +--- src/objective-c/GRPCClient/GRPCCall.m | 7 +++++++ src/objective-c/ProtoRPC/ProtoRPC.h | 4 +--- src/objective-c/ProtoRPC/ProtoRPC.m | 11 +++++++++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 48f4514a06..6adecec144 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -174,9 +174,7 @@ extern id const kGRPCTrailersKey; /** * All the responses must be issued to a user-provided dispatch queue. This property specifies the - * dispatch queue to be used for issuing the notifications. A serial queue should be provided if - * the order of responses (initial metadata, message, message, ..., message, trailing metadata) - * needs to be maintained. + * dispatch queue to be used for issuing the notifications. */ @property(atomic, readonly) dispatch_queue_t dispatchQueue; diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 50c38ed99e..917788e9f2 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -101,6 +101,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; } + if (requestOptions.safety > GRPCCallSafetyCacheableRequest) { + [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; + } + if (responseHandler == nil) { + [NSException raise:NSInvalidArgumentException format:@"Response handler required."]; + } if ((self = [super init])) { _requestOptions = [requestOptions copy]; @@ -114,6 +120,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Fallback on earlier versions _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } + dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); _started = NO; } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index d20098ce8c..db1e8c6deb 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -48,9 +48,7 @@ /** * All the responses must be issued to a user-provided dispatch queue. This property specifies the - * dispatch queue to be used for issuing the notifications. A serial queue should be provided if - * the order of responses (initial metadata, message, message, ..., message, trailing metadata) - * needs to be maintained. + * dispatch queue to be used for issuing the notifications. */ @property(atomic, readonly) dispatch_queue_t dispatchQueue; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index b860515d4e..9fb398408b 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -72,6 +72,16 @@ responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { + if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; + } + if (requestOptions.safety > GRPCCallSafetyCacheableRequest) { + [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; + } + if (handler == nil) { + [NSException raise:NSInvalidArgumentException format:@"Response handler required."]; + } + if ((self = [super init])) { _requestOptions = [requestOptions copy]; _handler = handler; @@ -82,6 +92,7 @@ } else { _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); } + dispatch_set_target_queue(handler.dispatchQueue, _dispatchQueue); [self start]; } -- cgit v1.2.3 From a8b07a37df7680bbe853f4efa0c358447db946fe Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 17:39:51 -0700 Subject: Synchronized access to kHostCache --- src/objective-c/GRPCClient/private/GRPCHost.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 429958b408..de6f09a44b 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -125,7 +125,10 @@ static NSMutableDictionary *kHostCache; if (hostURL.host && !hostURL.port) { address = [hostURL.host stringByAppendingString:@":443"]; } - GRPCHost *cachedHost = kHostCache[address]; + __block GRPCHost *cachedHost; + @synchronized (kHostCache) { + cachedHost = kHostCache[address]; + } return (cachedHost != nil); } -- cgit v1.2.3 From 543fbf38c0ad1690558f7be3d1c58ff445a8714f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 17:40:35 -0700 Subject: timeout > 0 --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 917788e9f2..16acca249d 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -753,7 +753,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (_serverName.length != 0) { callOptions.serverAuthority = _serverName; } - if (_timeout != 0) { + if (_timeout > 0) { callOptions.timeout = _timeout; } uint32_t callFlags = [GRPCCall callFlagsForHost:_host path:_path]; -- cgit v1.2.3 From 6032e960d43af5912d06553adc22012d3f7c758a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 18:06:13 -0700 Subject: Polish channelID comments --- src/objective-c/GRPCClient/GRPCCallOptions.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index ff575d09cf..e1a63f83b2 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -41,6 +41,7 @@ typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) { // The transport to be used by a gRPC call typedef NS_ENUM(NSInteger, GRPCTransportType) { + GRPCTransportTypeDefault = 0, // gRPC internal HTTP/2 stack with BoringSSL GRPCTransportTypeChttp2BoringSSL = 0, // Cronet stack @@ -180,8 +181,10 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { @property(copy, readonly) NSString *channelPoolDomain; /** - * Channel id allows a call to force creating a new channel (connection) rather than using a cached - * channel. Calls using distinct channelID will not get cached to the same connection. + * Channel id allows control of channel caching within a channelPoolDomain. A call with a unique + * channelID will create a new channel (connection) instead of reusing an existing one. Multiple + * calls in the same channelPoolDomain using identical channelID are allowed to share connection + * if other channel options are also the same. */ @property(readonly) NSUInteger channelID; -- cgit v1.2.3 From 62fb609df7b9534f188804c43401f6219345577c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 18:10:02 -0700 Subject: rename kChannelPool->gChannelPool --- src/objective-c/GRPCClient/private/GRPCChannel.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index cf44b96e22..ae90821de0 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -64,7 +64,7 @@ } - (void)unmanagedCallUnref { - [kChannelPool unrefChannelWithConfiguration:_configuration]; + [gChannelPool unrefChannelWithConfiguration:_configuration]; } - (nullable instancetype)initWithUnmanagedChannel:(nullable grpc_channel *)unmanagedChannel @@ -94,12 +94,12 @@ } static dispatch_once_t initChannelPool; -static GRPCChannelPool *kChannelPool; +static GRPCChannelPool *gChannelPool; + (nullable instancetype)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { dispatch_once(&initChannelPool, ^{ - kChannelPool = [[GRPCChannelPool alloc] init]; + gChannelPool = [[GRPCChannelPool alloc] init]; }); NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:host]]; @@ -109,7 +109,7 @@ static GRPCChannelPool *kChannelPool; GRPCChannelConfiguration *channelConfig = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; - return [kChannelPool channelWithConfiguration:channelConfig + return [gChannelPool channelWithConfiguration:channelConfig createChannel:^{ return [GRPCChannel createChannelWithConfiguration:channelConfig]; @@ -117,7 +117,7 @@ static GRPCChannelPool *kChannelPool; } + (void)closeOpenConnections { - [kChannelPool clear]; + [gChannelPool clear]; } @end -- cgit v1.2.3 From 549db7b80b3e6e91aaf08f9f9bf2f932050cc310 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 18:10:48 -0700 Subject: host == nil -> host.length == 0 --- src/objective-c/GRPCClient/private/GRPCChannel.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index ae90821de0..495af5ebe8 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -82,7 +82,7 @@ + (nullable instancetype)createChannelWithConfiguration:(GRPCChannelConfiguration *)config { NSString *host = config.host; - if (host == nil || [host length] == 0) { + if (host.length == 0) { return nil; } -- cgit v1.2.3 From bc292b87c26ea8f6465443a152e86b3ed71e585b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 18:14:34 -0700 Subject: polish attributes of GRPCChannelConfiguration --- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 4 ++-- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 1145039549..2a99089d2f 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -31,8 +31,8 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCChannelConfiguration : NSObject -@property(atomic, strong, readwrite) NSString *host; -@property(atomic, strong, readwrite) GRPCCallOptions *callOptions; +@property(copy, readonly) NSString *host; +@property(strong, readonly) GRPCCallOptions *callOptions; @property(readonly) id channelFactory; @property(readonly) NSMutableDictionary *channelArgs; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 37e42f8c75..10a15f5255 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -141,9 +141,7 @@ const NSTimeInterval kChannelDestroyDelay = 30; } - (nonnull id)copyWithZone:(nullable NSZone *)zone { - GRPCChannelConfiguration *newConfig = [[GRPCChannelConfiguration alloc] init]; - newConfig.host = _host; - newConfig.callOptions = _callOptions; + GRPCChannelConfiguration *newConfig = [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; return newConfig; } -- cgit v1.2.3 From ad5485ae4ef4ec31cb6b3ed54876fd9868343388 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 16 Oct 2018 18:28:16 -0700 Subject: Make channel args immutable --- src/objective-c/GRPCClient/private/GRPCChannel.m | 10 ++++++++-- src/objective-c/GRPCClient/private/GRPCChannelFactory.h | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h | 2 +- src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m | 4 ++-- .../GRPCClient/private/GRPCInsecureChannelFactory.h | 2 +- .../GRPCClient/private/GRPCInsecureChannelFactory.m | 2 +- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h | 2 +- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m | 2 +- 10 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 495af5ebe8..2274fa5d6a 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -86,8 +86,14 @@ return nil; } - NSMutableDictionary *channelArgs = config.channelArgs; - [channelArgs addEntriesFromDictionary:config.callOptions.additionalChannelArgs]; + NSDictionary *channelArgs; + if (config.callOptions.additionalChannelArgs.count != 0) { + NSMutableDictionary *args = [config.channelArgs copy]; + [args addEntriesFromDictionary:config.callOptions.additionalChannelArgs]; + channelArgs = args; + } else { + channelArgs = config.channelArgs; + } id factory = config.channelFactory; grpc_channel *unmanaged_channel = [factory createChannelWithHost:host channelArgs:channelArgs]; return [[GRPCChannel alloc] initWithUnmanagedChannel:unmanaged_channel configuration:config]; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h index e44f8260df..492145da80 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol GRPCChannelFactory - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableDictionary *)args; + channelArgs:(nullable NSDictionary *)args; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 2a99089d2f..1984919fa7 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN @property(strong, readonly) GRPCCallOptions *callOptions; @property(readonly) id channelFactory; -@property(readonly) NSMutableDictionary *channelArgs; +@property(readonly) NSDictionary *channelArgs; - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 10a15f5255..11c9d4be8d 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -76,7 +76,7 @@ const NSTimeInterval kChannelDestroyDelay = 30; } } -- (NSMutableDictionary *)channelArgs { +- (NSDictionary *)channelArgs { NSMutableDictionary *args = [NSMutableDictionary new]; NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING; diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h index 97e1ae920a..738dfdb737 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h @@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN + (nullable instancetype)sharedInstance; - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableDictionary *)args; + channelArgs:(nullable NSDictionary *)args; - (nullable instancetype)init NS_UNAVAILABLE; diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index 5c0fe16d39..00b388ebbe 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -53,7 +53,7 @@ NS_ASSUME_NONNULL_BEGIN } - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableDictionary *)args { + channelArgs:(nullable NSDictionary *)args { // Remove client authority filter since that is not supported args[@GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER] = [NSNumber numberWithInt:1]; @@ -81,7 +81,7 @@ NS_ASSUME_NONNULL_BEGIN } - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableArray *)args { + channelArgs:(nullable NSDictionary *)args { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; return nil; diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h index 905a181ca7..2d471aebed 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h @@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN + (nullable instancetype)sharedInstance; - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableDictionary *)args; + channelArgs:(nullable NSDictionary *)args; - (nullable instancetype)init NS_UNAVAILABLE; diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m index 41860bf6ff..d969b887b4 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN } - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableDictionary *)args { + channelArgs:(nullable NSDictionary *)args { grpc_channel_args *coreChannelArgs = BuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h index ab5eee478e..82af0dc3e6 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN error:(NSError **)errorPtr; - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableDictionary *)args; + channelArgs:(nullable NSDictionary *)args; - (nullable instancetype)init NS_UNAVAILABLE; diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index a0d56e4bdc..277823c4e3 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -110,7 +110,7 @@ NS_ASSUME_NONNULL_BEGIN } - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSMutableArray *)args { + channelArgs:(nullable NSDictionary *)args { grpc_channel_args *coreChannelArgs = BuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); -- cgit v1.2.3 From da42aa1c1ba38a12450e6b75b20281d6603b3d7e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 10:06:07 -0700 Subject: Add designated initializer annotation --- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 1984919fa7..5ceb0b6d82 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init; -- (instancetype)initWithChannelDestroyDelay:(NSTimeInterval)channelDestroyDelay; +- (instancetype)initWithChannelDestroyDelay:(NSTimeInterval)channelDestroyDelay NS_DESIGNATED_INITIALIZER; /** * Return a channel with a particular configuration. If the channel does not exist, execute \a -- cgit v1.2.3 From 677ab86b4a8567197550d6969a4d5bd76b8206e1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 10:33:38 -0700 Subject: rename createChannel -> createChannelCallback --- src/objective-c/GRPCClient/private/GRPCChannel.m | 8 ++++---- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 2274fa5d6a..bea75d25a9 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -116,10 +116,10 @@ static GRPCChannelPool *gChannelPool; GRPCChannelConfiguration *channelConfig = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; return [gChannelPool channelWithConfiguration:channelConfig - createChannel:^{ - return - [GRPCChannel createChannelWithConfiguration:channelConfig]; - }]; + createChannelCallback:^{ + return + [GRPCChannel createChannelWithConfiguration:channelConfig]; + }]; } + (void)closeOpenConnections { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 5ceb0b6d82..48c35eacb0 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -56,7 +56,7 @@ NS_ASSUME_NONNULL_BEGIN * createChannel then add it in the pool. If the channel exists, increase its reference count. */ - (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration - createChannel:(GRPCChannel * (^)(void))createChannel; + createChannelCallback:(GRPCChannel * (^)(void))createChannelCallback; /** Decrease a channel's refcount. */ - (void)unrefChannelWithConfiguration:configuration; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 11c9d4be8d..680b268dcf 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -338,14 +338,14 @@ const NSTimeInterval kChannelDestroyDelay = 30; } - (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration - createChannel:(GRPCChannel * (^)(void))createChannel { + createChannelCallback:(GRPCChannel * (^)(void))createChannelCallback { __block GRPCChannel *channel; dispatch_sync(_dispatchQueue, ^{ if ([self->_channelPool objectForKey:configuration]) { [self->_callRefs[configuration] refChannel]; channel = self->_channelPool[configuration]; } else { - channel = createChannel(); + channel = createChannelCallback(); self->_channelPool[configuration] = channel; GRPCChannelCallRef *callRef = [[GRPCChannelCallRef alloc] -- cgit v1.2.3 From 86ff72bb4736cb9333505baeb324386cfa24bcb9 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 10:49:30 -0700 Subject: Add missing type information --- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 680b268dcf..c46b9ddfc8 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -363,7 +363,7 @@ const NSTimeInterval kChannelDestroyDelay = 30; return channel; } -- (void)unrefChannelWithConfiguration:configuration { +- (void)unrefChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { dispatch_sync(_dispatchQueue, ^{ if ([self->_channelPool objectForKey:configuration]) { [self->_callRefs[configuration] unrefChannel]; -- cgit v1.2.3 From 8fef0c87893ceda1c5bb7aaa09ddb8dfaefacbdb Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 16:59:00 -0700 Subject: Rewrite the channel pool --- src/objective-c/GRPCClient/GRPCCall.m | 9 +- src/objective-c/GRPCClient/private/GRPCChannel.h | 13 +- src/objective-c/GRPCClient/private/GRPCChannel.m | 204 ++++++++++++++++++--- .../GRPCClient/private/GRPCChannelPool.h | 14 +- .../GRPCClient/private/GRPCChannelPool.m | 139 +++----------- .../tests/ChannelTests/ChannelPoolTest.m | 109 +++++------ 6 files changed, 262 insertions(+), 226 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 16acca249d..5ffdfbaa89 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -718,7 +718,14 @@ const char *kCFStreamVarName = "grpc_cfstream"; [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions]; - NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?"); + if (_wrappedCall == nil) { + [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : @"Failed to create call from channel." + }]]; + return; + } [self sendHeaders]; [self invokeCall]; diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 7d5039a8a2..7a40638dc3 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -39,6 +39,11 @@ struct grpc_channel_credentials; + (nullable instancetype)channelWithHost:(nonnull NSString *)host callOptions:(nullable GRPCCallOptions *)callOptions; +/** + * Create a channel object with the signature \a config. + */ ++ (nullable instancetype)createChannelWithConfiguration:(nonnull GRPCChannelConfiguration *)config; + /** * Get a grpc core call object from this channel. */ @@ -46,13 +51,11 @@ struct grpc_channel_credentials; completionQueue:(nonnull GRPCCompletionQueue *)queue callOptions:(nonnull GRPCCallOptions *)callOptions; +- (void)unmanagedCallRef; + - (void)unmanagedCallUnref; -/** - * Create a channel object with the signature \a config. This function is used for testing only. Use - * channelWithHost:callOptions: in production. - */ -+ (nullable instancetype)createChannelWithConfiguration:(nonnull GRPCChannelConfiguration *)config; +- (void)disconnect; // TODO (mxyan): deprecate with GRPCCall:closeOpenConnections + (void)closeOpenConnections; diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index bea75d25a9..9e7e1ea1fc 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -24,7 +24,6 @@ #import "GRPCChannelFactory.h" #import "GRPCChannelPool.h" #import "GRPCCompletionQueue.h" -#import "GRPCConnectivityMonitor.h" #import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" @@ -33,38 +32,180 @@ #import #import +// When all calls of a channel are destroyed, destroy the channel after this much seconds. +NSTimeInterval kChannelDestroyDelay = 30; + +/** + * Time the channel destroy when the channel's calls are unreffed. If there's new call, reset the + * timer. + */ +@interface GRPCChannelRef : NSObject + +- (instancetype)initWithDestroyDelay:(NSTimeInterval)destroyDelay + destroyChannelCallback:(void (^)())destroyChannelCallback; + +/** Add call ref count to the channel and maybe reset the timer. */ +- (void)refChannel; + +/** Reduce call ref count to the channel and maybe set the timer. */ +- (void)unrefChannel; + +/** Disconnect the channel immediately. */ +- (void)disconnect; + +@end + +@implementation GRPCChannelRef { + NSTimeInterval _destroyDelay; + // We use dispatch queue for this purpose since timer invalidation must happen on the same + // thread which issued the timer. + dispatch_queue_t _dispatchQueue; + void (^_destroyChannelCallback)(); + + NSUInteger _refCount; + NSTimer *_timer; + BOOL _disconnected; +} + +- (instancetype)initWithDestroyDelay:(NSTimeInterval)destroyDelay + destroyChannelCallback:(void (^)())destroyChannelCallback { + if ((self = [super init])) { + _destroyDelay = destroyDelay; + _destroyChannelCallback = destroyChannelCallback; + + _refCount = 1; + _timer = nil; + _disconnected = NO; + } + return self; +} + +// This function is protected by channel dispatch queue. +- (void)refChannel { + if (!_disconnected) { + _refCount++; + if (_timer) { + [_timer invalidate]; + _timer = nil; + } + } +} + +// This function is protected by channel dispatch queue. +- (void)unrefChannel { + if (!_disconnected) { + _refCount--; + if (_refCount == 0) { + if (_timer) { + [_timer invalidate]; + } + _timer = [NSTimer scheduledTimerWithTimeInterval:self->_destroyDelay + target:self + selector:@selector(timerFire:) + userInfo:nil + repeats:NO]; + } + } +} + +// This function is protected by channel dispatch queue. +- (void)disconnect { + if (!_disconnected) { + if (self->_timer != nil) { + [self->_timer invalidate]; + self->_timer = nil; + } + _disconnected = YES; + // Break retain loop + _destroyChannelCallback = nil; + } +} + +// This function is protected by channel dispatch queue. +- (void)timerFire:(NSTimer *)timer { + if (_disconnected || _timer == nil || _timer != timer) { + return; + } + _timer = nil; + _destroyChannelCallback(); + // Break retain loop + _destroyChannelCallback = nil; + _disconnected = YES; +} + +@end + @implementation GRPCChannel { GRPCChannelConfiguration *_configuration; grpc_channel *_unmanagedChannel; + GRPCChannelRef *_channelRef; + dispatch_queue_t _dispatchQueue; } - (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(nonnull GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions { - NSString *serverAuthority = callOptions.serverAuthority; - NSTimeInterval timeout = callOptions.timeout; - GPR_ASSERT(timeout >= 0); - grpc_slice host_slice = grpc_empty_slice(); - if (serverAuthority) { - host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); - } - grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); - gpr_timespec deadline_ms = + __block grpc_call *call = nil; + dispatch_sync(_dispatchQueue, ^{ + if (self->_unmanagedChannel) { + NSString *serverAuthority = callOptions.serverAuthority; + NSTimeInterval timeout = callOptions.timeout; + GPR_ASSERT(timeout >= 0); + grpc_slice host_slice = grpc_empty_slice(); + if (serverAuthority) { + host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); + } + grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); + gpr_timespec deadline_ms = timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); - grpc_call *call = grpc_channel_create_call( - _unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, - serverAuthority ? &host_slice : NULL, deadline_ms, NULL); - if (serverAuthority) { - grpc_slice_unref(host_slice); - } - grpc_slice_unref(path_slice); + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + call = grpc_channel_create_call( + self->_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, + serverAuthority ? &host_slice : NULL, deadline_ms, NULL); + if (serverAuthority) { + grpc_slice_unref(host_slice); + } + grpc_slice_unref(path_slice); + } + }); return call; } +- (void)unmanagedCallRef { + dispatch_async(_dispatchQueue, ^{ + if (self->_unmanagedChannel) { + [self->_channelRef refChannel]; + } + }); +} + - (void)unmanagedCallUnref { - [gChannelPool unrefChannelWithConfiguration:_configuration]; + dispatch_async(_dispatchQueue, ^{ + if (self->_unmanagedChannel) { + [self->_channelRef unrefChannel]; + } + }); +} + +- (void)disconnect { + dispatch_async(_dispatchQueue, ^{ + if (self->_unmanagedChannel) { + grpc_channel_destroy(self->_unmanagedChannel); + self->_unmanagedChannel = nil; + [self->_channelRef disconnect]; + } + }); +} + +- (void)destroyChannel { + dispatch_async(_dispatchQueue, ^{ + if (self->_unmanagedChannel) { + grpc_channel_destroy(self->_unmanagedChannel); + self->_unmanagedChannel = nil; + [gChannelPool removeChannelWithConfiguration:self->_configuration]; + } + }); } - (nullable instancetype)initWithUnmanagedChannel:(nullable grpc_channel *)unmanagedChannel @@ -72,12 +213,22 @@ if ((self = [super init])) { _unmanagedChannel = unmanagedChannel; _configuration = configuration; + _channelRef = [[GRPCChannelRef alloc] initWithDestroyDelay:kChannelDestroyDelay destroyChannelCallback:^{ + [self destroyChannel]; + }]; + if (@available(iOS 8.0, *)) { + _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + } else { + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } } return self; } - (void)dealloc { - grpc_channel_destroy(_unmanagedChannel); + if (_unmanagedChannel) { + grpc_channel_destroy(_unmanagedChannel); + } } + (nullable instancetype)createChannelWithConfiguration:(GRPCChannelConfiguration *)config { @@ -88,7 +239,7 @@ NSDictionary *channelArgs; if (config.callOptions.additionalChannelArgs.count != 0) { - NSMutableDictionary *args = [config.channelArgs copy]; + NSMutableDictionary *args = [config.channelArgs mutableCopy]; [args addEntriesFromDictionary:config.callOptions.additionalChannelArgs]; channelArgs = args; } else { @@ -115,15 +266,12 @@ static GRPCChannelPool *gChannelPool; GRPCChannelConfiguration *channelConfig = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; - return [gChannelPool channelWithConfiguration:channelConfig - createChannelCallback:^{ - return - [GRPCChannel createChannelWithConfiguration:channelConfig]; - }]; + + return [gChannelPool channelWithConfiguration:channelConfig]; } + (void)closeOpenConnections { - [gChannelPool clear]; + [gChannelPool removeAndCloseAllChannels]; } @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 48c35eacb0..bd1350c15d 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -49,20 +49,20 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init; -- (instancetype)initWithChannelDestroyDelay:(NSTimeInterval)channelDestroyDelay NS_DESIGNATED_INITIALIZER; - /** * Return a channel with a particular configuration. If the channel does not exist, execute \a * createChannel then add it in the pool. If the channel exists, increase its reference count. */ -- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration - createChannelCallback:(GRPCChannel * (^)(void))createChannelCallback; +- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration; -/** Decrease a channel's refcount. */ -- (void)unrefChannelWithConfiguration:configuration; +/** Remove a channel with particular configuration. */ +- (void)removeChannelWithConfiguration:(GRPCChannelConfiguration *)configuration; /** Clear all channels in the pool. */ -- (void)clear; +- (void)removeAllChannels; + +/** Clear all channels in the pool and destroy the channels. */ +- (void)removeAndCloseAllChannels; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index c46b9ddfc8..7c0a8a8621 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -18,6 +18,7 @@ #import +#import "GRPCChannel.h" #import "GRPCChannelFactory.h" #import "GRPCChannelPool.h" #import "GRPCConnectivityMonitor.h" @@ -31,9 +32,6 @@ extern const char *kCFStreamVarName; -// When all calls of a channel are destroyed, destroy the channel after this much seconds. -const NSTimeInterval kChannelDestroyDelay = 30; - @implementation GRPCChannelConfiguration - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { @@ -216,109 +214,22 @@ const NSTimeInterval kChannelDestroyDelay = 30; @end -/** - * Time the channel destroy when the channel's calls are unreffed. If there's new call, reset the - * timer. - */ -@interface GRPCChannelCallRef : NSObject - -- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)configuration - destroyDelay:(NSTimeInterval)destroyDelay - dispatchQueue:(dispatch_queue_t)dispatchQueue - destroyChannel:(void (^)())destroyChannel; - -/** Add call ref count to the channel and maybe reset the timer. */ -- (void)refChannel; - -/** Reduce call ref count to the channel and maybe set the timer. */ -- (void)unrefChannel; - -@end - -@implementation GRPCChannelCallRef { - GRPCChannelConfiguration *_configuration; - NSTimeInterval _destroyDelay; - // We use dispatch queue for this purpose since timer invalidation must happen on the same - // thread which issued the timer. - dispatch_queue_t _dispatchQueue; - void (^_destroyChannel)(); - - NSUInteger _refCount; - NSTimer *_timer; -} - -- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)configuration - destroyDelay:(NSTimeInterval)destroyDelay - dispatchQueue:(dispatch_queue_t)dispatchQueue - destroyChannel:(void (^)())destroyChannel { - if ((self = [super init])) { - _configuration = configuration; - _destroyDelay = destroyDelay; - _dispatchQueue = dispatchQueue; - _destroyChannel = destroyChannel; - - _refCount = 0; - _timer = nil; - } - return self; -} - -// This function is protected by channel pool dispatch queue. -- (void)refChannel { - _refCount++; - if (_timer) { - [_timer invalidate]; - } - _timer = nil; -} - -// This function is protected by channel spool dispatch queue. -- (void)unrefChannel { - self->_refCount--; - if (self->_refCount == 0) { - if (self->_timer) { - [self->_timer invalidate]; - } - self->_timer = [NSTimer scheduledTimerWithTimeInterval:self->_destroyDelay - target:self - selector:@selector(timerFire:) - userInfo:nil - repeats:NO]; - } -} - -- (void)timerFire:(NSTimer *)timer { - dispatch_sync(_dispatchQueue, ^{ - if (self->_timer == nil || self->_timer != timer) { - return; - } - self->_timer = nil; - self->_destroyChannel(self->_configuration); - }); -} - -@end - #pragma mark GRPCChannelPool @implementation GRPCChannelPool { - NSTimeInterval _channelDestroyDelay; NSMutableDictionary *_channelPool; - NSMutableDictionary *_callRefs; // Dedicated queue for timer dispatch_queue_t _dispatchQueue; } - (instancetype)init { - return [self initWithChannelDestroyDelay:kChannelDestroyDelay]; -} - -- (instancetype)initWithChannelDestroyDelay:(NSTimeInterval)channelDestroyDelay { if ((self = [super init])) { - _channelDestroyDelay = channelDestroyDelay; _channelPool = [NSMutableDictionary dictionary]; - _callRefs = [NSMutableDictionary dictionary]; - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + if (@available(iOS 8.0, *)) { + _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + } else { + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } // Connectivity monitor is not required for CFStream char *enableCFStream = getenv(kCFStreamVarName); @@ -337,49 +248,43 @@ const NSTimeInterval kChannelDestroyDelay = 30; } } -- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration - createChannelCallback:(GRPCChannel * (^)(void))createChannelCallback { +- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration { __block GRPCChannel *channel; dispatch_sync(_dispatchQueue, ^{ if ([self->_channelPool objectForKey:configuration]) { - [self->_callRefs[configuration] refChannel]; channel = self->_channelPool[configuration]; + [channel unmanagedCallRef]; } else { - channel = createChannelCallback(); + channel = [GRPCChannel createChannelWithConfiguration:configuration]; self->_channelPool[configuration] = channel; - - GRPCChannelCallRef *callRef = [[GRPCChannelCallRef alloc] - initWithChannelConfiguration:configuration - destroyDelay:self->_channelDestroyDelay - dispatchQueue:self->_dispatchQueue - destroyChannel:^(GRPCChannelConfiguration *configuration) { - [self->_channelPool removeObjectForKey:configuration]; - [self->_callRefs removeObjectForKey:configuration]; - }]; - [callRef refChannel]; - self->_callRefs[configuration] = callRef; } }); return channel; } -- (void)unrefChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { +- (void)removeChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { + dispatch_async(_dispatchQueue, ^{ + [self->_channelPool removeObjectForKey:configuration]; + }); +} + +- (void)removeAllChannels { dispatch_sync(_dispatchQueue, ^{ - if ([self->_channelPool objectForKey:configuration]) { - [self->_callRefs[configuration] unrefChannel]; - } + self->_channelPool = [NSMutableDictionary dictionary]; }); } -- (void)clear { +- (void)removeAndCloseAllChannels { dispatch_sync(_dispatchQueue, ^{ + [self->_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannel * _Nonnull obj, BOOL * _Nonnull stop) { + [obj disconnect]; + }]; self->_channelPool = [NSMutableDictionary dictionary]; - self->_callRefs = [NSMutableDictionary dictionary]; }); } - (void)connectivityChange:(NSNotification *)note { - [self clear]; + [self removeAndCloseAllChannels]; } @end diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index 9e1c9eca74..b195b747a1 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -44,83 +44,68 @@ NSString *kDummyHost = @"dummy.host"; [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; GRPCChannelConfiguration *config2 = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; - GRPCChannelPool *pool = [[GRPCChannelPool alloc] initWithChannelDestroyDelay:1]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - __weak XCTestExpectation *expectCreateChannel = - [self expectationWithDescription:@"Create first channel"]; - GRPCChannel *channel1 = - [pool channelWithConfiguration:config1 - createChannel:^{ - [expectCreateChannel fulfill]; - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; - GRPCChannel *channel2 = [pool channelWithConfiguration:config2 - createChannel:^{ - XCTFail(@"Should not create a second channel."); - return (GRPCChannel *)nil; - }]; + GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; + GRPCChannel *channel2 = [pool channelWithConfiguration:config2]; XCTAssertEqual(channel1, channel2); } -- (void)testChannelTimeout { - NSTimeInterval kChannelDestroyDelay = 1.0; +- (void)testChannelRemove { GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; options1.transportType = GRPCTransportTypeInsecure; GRPCChannelConfiguration *config1 = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; - GRPCChannelPool *pool = - [[GRPCChannelPool alloc] initWithChannelDestroyDelay:kChannelDestroyDelay]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; GRPCChannel *channel1 = - [pool channelWithConfiguration:config1 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; - [pool unrefChannelWithConfiguration:config1]; - __weak XCTestExpectation *expectTimerDone = [self expectationWithDescription:@"Timer elapse."]; - NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:kChannelDestroyDelay + 1 - repeats:NO - block:^(NSTimer *_Nonnull timer) { - [expectTimerDone fulfill]; - }]; - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; - timer = nil; + [pool channelWithConfiguration:config1]; + [pool removeChannelWithConfiguration:config1]; GRPCChannel *channel2 = - [pool channelWithConfiguration:config1 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; + [pool channelWithConfiguration:config1]; XCTAssertNotEqual(channel1, channel2); } +extern NSTimeInterval kChannelDestroyDelay; + - (void)testChannelTimeoutCancel { - NSTimeInterval kChannelDestroyDelay = 3.0; + NSTimeInterval kOriginalInterval = kChannelDestroyDelay; + kChannelDestroyDelay = 3.0; GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; options1.transportType = GRPCTransportTypeInsecure; GRPCChannelConfiguration *config1 = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; GRPCChannelPool *pool = - [[GRPCChannelPool alloc] initWithChannelDestroyDelay:kChannelDestroyDelay]; + [[GRPCChannelPool alloc] init]; GRPCChannel *channel1 = - [pool channelWithConfiguration:config1 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; + [pool channelWithConfiguration:config1]; [channel1 unmanagedCallUnref]; sleep(1); GRPCChannel *channel2 = - [pool channelWithConfiguration:config1 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; + [pool channelWithConfiguration:config1]; XCTAssertEqual(channel1, channel2); sleep((int)kChannelDestroyDelay + 2); GRPCChannel *channel3 = - [pool channelWithConfiguration:config1 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; + [pool channelWithConfiguration:config1]; XCTAssertEqual(channel1, channel3); + kChannelDestroyDelay = kOriginalInterval; +} + +- (void)testChannelDisconnect { + NSString *kDummyHost = @"dummy.host"; + GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; + options1.transportType = GRPCTransportTypeInsecure; + GRPCCallOptions *options2 = [options1 copy]; + GRPCChannelConfiguration *config1 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; + GRPCChannelConfiguration *config2 = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + + + GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; + [pool removeAndCloseAllChannels]; + GRPCChannel *channel2 = [pool channelWithConfiguration:config2]; + XCTAssertNotEqual(channel1, channel2); } - (void)testClearChannels { @@ -132,31 +117,19 @@ NSString *kDummyHost = @"dummy.host"; [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; GRPCChannelConfiguration *config2 = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; - GRPCChannelPool *pool = [[GRPCChannelPool alloc] initWithChannelDestroyDelay:1]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; GRPCChannel *channel1 = - [pool channelWithConfiguration:config1 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; + [pool channelWithConfiguration:config1]; GRPCChannel *channel2 = - [pool channelWithConfiguration:config2 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config2]; - }]; + [pool channelWithConfiguration:config2]; XCTAssertNotEqual(channel1, channel2); - [pool clear]; + [pool removeAndCloseAllChannels]; GRPCChannel *channel3 = - [pool channelWithConfiguration:config1 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config1]; - }]; + [pool channelWithConfiguration:config1]; GRPCChannel *channel4 = - [pool channelWithConfiguration:config2 - createChannel:^{ - return [GRPCChannel createChannelWithConfiguration:config2]; - }]; + [pool channelWithConfiguration:config2]; XCTAssertNotEqual(channel1, channel3); XCTAssertNotEqual(channel2, channel4); } -- cgit v1.2.3 From d47f4b4c23a9dab2813e9b521d2545ea26d0105c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 17:06:16 -0700 Subject: Check return value rather than error --- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 7c0a8a8621..740eeaf6cf 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -36,8 +36,8 @@ extern const char *kCFStreamVarName; - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { if ((self = [super init])) { - _host = host; - _callOptions = callOptions; + _host = [host copy]; + _callOptions = [callOptions copy]; } return self; } @@ -56,9 +56,8 @@ extern const char *kCFStreamVarName; privateKey:_callOptions.PEMPrivateKey certChain:_callOptions.PEMCertChain error:&error]; - if (error) { + if (factory == nil) { NSLog(@"Error creating secure channel factory: %@", error); - return nil; } return factory; #ifdef GRPC_COMPILE_WITH_CRONET -- cgit v1.2.3 From f48c90606f246afab3a2aa1e1547578c4c34292a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 17:46:09 -0700 Subject: Add isChannelOptionsEqualTo: to GRPCCallOptions --- src/objective-c/GRPCClient/GRPCCallOptions.h | 5 +++ src/objective-c/GRPCClient/GRPCCallOptions.m | 40 ++++++++++++++++++++++ .../GRPCClient/private/GRPCChannelPool.m | 38 +------------------- 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index e1a63f83b2..bf03938b27 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -188,6 +188,11 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { */ @property(readonly) NSUInteger channelID; +/** + * Return if the channel options are equal to another object. + */ +- (BOOL)isChannelOptionsEqualTo:(GRPCCallOptions *)callOptions; + @end @interface GRPCMutableCallOptions : GRPCCallOptions diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index b19917d778..1fc8c9fb1a 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -227,6 +227,46 @@ static NSUInteger kDefaultChannelID = 0; return newOptions; } +- (BOOL)isChannelOptionsEqualTo:(GRPCCallOptions *)callOptions { + if (!(callOptions.userAgentPrefix == _userAgentPrefix || + [callOptions.userAgentPrefix isEqualToString:_userAgentPrefix])) + return NO; + if (!(callOptions.responseSizeLimit == _responseSizeLimit)) return NO; + if (!(callOptions.compressAlgorithm == _compressAlgorithm)) return NO; + if (!(callOptions.enableRetry == _enableRetry)) return NO; + if (!(callOptions.keepaliveInterval == _keepaliveInterval)) return NO; + if (!(callOptions.keepaliveTimeout == _keepaliveTimeout)) return NO; + if (!(callOptions.connectMinTimeout == _connectMinTimeout)) return NO; + if (!(callOptions.connectInitialBackoff == _connectInitialBackoff)) return NO; + if (!(callOptions.connectMaxBackoff == _connectMaxBackoff)) return NO; + if (!(callOptions.additionalChannelArgs == _additionalChannelArgs || + [callOptions.additionalChannelArgs + isEqualToDictionary:_additionalChannelArgs])) + return NO; + if (!(callOptions.PEMRootCertificates == _PEMRootCertificates || + [callOptions.PEMRootCertificates isEqualToString:_PEMRootCertificates])) + return NO; + if (!(callOptions.PEMPrivateKey == _PEMPrivateKey || + [callOptions.PEMPrivateKey isEqualToString:_PEMPrivateKey])) + return NO; + if (!(callOptions.PEMCertChain == _PEMCertChain || + [callOptions.PEMCertChain isEqualToString:_PEMCertChain])) + return NO; + if (!(callOptions.hostNameOverride == _hostNameOverride || + [callOptions.hostNameOverride isEqualToString:_hostNameOverride])) + return NO; + if (!(callOptions.transportType == _transportType)) return NO; + if (!(callOptions.logContext == _logContext || + [callOptions.logContext isEqual:_logContext])) + return NO; + if (!(callOptions.channelPoolDomain == _channelPoolDomain || + [callOptions.channelPoolDomain isEqualToString:_channelPoolDomain])) + return NO; + if (!(callOptions.channelID == _channelID)) return NO; + + return YES; +} + @end @implementation GRPCMutableCallOptions diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 740eeaf6cf..995212fdb6 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -68,8 +68,6 @@ extern const char *kCFStreamVarName; return [GRPCCronetChannelFactory sharedInstance]; case GRPCTransportTypeInsecure: return [GRPCInsecureChannelFactory sharedInstance]; - default: - GPR_UNREACHABLE_CODE(return nil); } } @@ -147,41 +145,7 @@ extern const char *kCFStreamVarName; NSAssert([object isKindOfClass:[GRPCChannelConfiguration class]], @"Illegal :isEqual"); GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; if (!(obj.host == _host || [obj.host isEqualToString:_host])) return NO; - if (!(obj.callOptions.userAgentPrefix == _callOptions.userAgentPrefix || - [obj.callOptions.userAgentPrefix isEqualToString:_callOptions.userAgentPrefix])) - return NO; - if (!(obj.callOptions.responseSizeLimit == _callOptions.responseSizeLimit)) return NO; - if (!(obj.callOptions.compressAlgorithm == _callOptions.compressAlgorithm)) return NO; - if (!(obj.callOptions.enableRetry == _callOptions.enableRetry)) return NO; - if (!(obj.callOptions.keepaliveInterval == _callOptions.keepaliveInterval)) return NO; - if (!(obj.callOptions.keepaliveTimeout == _callOptions.keepaliveTimeout)) return NO; - if (!(obj.callOptions.connectMinTimeout == _callOptions.connectMinTimeout)) return NO; - if (!(obj.callOptions.connectInitialBackoff == _callOptions.connectInitialBackoff)) return NO; - if (!(obj.callOptions.connectMaxBackoff == _callOptions.connectMaxBackoff)) return NO; - if (!(obj.callOptions.additionalChannelArgs == _callOptions.additionalChannelArgs || - [obj.callOptions.additionalChannelArgs - isEqualToDictionary:_callOptions.additionalChannelArgs])) - return NO; - if (!(obj.callOptions.PEMRootCertificates == _callOptions.PEMRootCertificates || - [obj.callOptions.PEMRootCertificates isEqualToString:_callOptions.PEMRootCertificates])) - return NO; - if (!(obj.callOptions.PEMPrivateKey == _callOptions.PEMPrivateKey || - [obj.callOptions.PEMPrivateKey isEqualToString:_callOptions.PEMPrivateKey])) - return NO; - if (!(obj.callOptions.PEMCertChain == _callOptions.PEMCertChain || - [obj.callOptions.PEMCertChain isEqualToString:_callOptions.PEMCertChain])) - return NO; - if (!(obj.callOptions.hostNameOverride == _callOptions.hostNameOverride || - [obj.callOptions.hostNameOverride isEqualToString:_callOptions.hostNameOverride])) - return NO; - if (!(obj.callOptions.transportType == _callOptions.transportType)) return NO; - if (!(obj.callOptions.logContext == _callOptions.logContext || - [obj.callOptions.logContext isEqual:_callOptions.logContext])) - return NO; - if (!(obj.callOptions.channelPoolDomain == _callOptions.channelPoolDomain || - [obj.callOptions.channelPoolDomain isEqualToString:_callOptions.channelPoolDomain])) - return NO; - if (!(obj.callOptions.channelID == _callOptions.channelID)) return NO; + if (!(obj.callOptions == _callOptions || [obj.callOptions isChannelOptionsEqualTo:_callOptions])) return NO; return YES; } -- cgit v1.2.3 From d578b4321812715de7fe615a1ae8624fd05f1c69 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 18:01:14 -0700 Subject: Add channelOptionsHash: to GRPCCChannelOptions --- src/objective-c/GRPCClient/GRPCCallOptions.h | 5 +++++ src/objective-c/GRPCClient/GRPCCallOptions.m | 24 ++++++++++++++++++++++ .../GRPCClient/private/GRPCChannelPool.m | 19 +---------------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index bf03938b27..8864bcb8a2 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -193,6 +193,11 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { */ - (BOOL)isChannelOptionsEqualTo:(GRPCCallOptions *)callOptions; +/** + * Hash for channel options. + */ +@property(readonly) NSUInteger channelOptionsHash; + @end @interface GRPCMutableCallOptions : GRPCCallOptions diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 1fc8c9fb1a..8d2b84b748 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -267,6 +267,30 @@ static NSUInteger kDefaultChannelID = 0; return YES; } +- (NSUInteger)channelOptionsHash { + NSUInteger result = 0; + result ^= _userAgentPrefix.hash; + result ^= _responseSizeLimit; + result ^= _compressAlgorithm; + result ^= _enableRetry; + result ^= (unsigned int)(_keepaliveInterval * 1000); + result ^= (unsigned int)(_keepaliveTimeout * 1000); + result ^= (unsigned int)(_connectMinTimeout * 1000); + result ^= (unsigned int)(_connectInitialBackoff * 1000); + result ^= (unsigned int)(_connectMaxBackoff * 1000); + result ^= _additionalChannelArgs.hash; + result ^= _PEMRootCertificates.hash; + result ^= _PEMPrivateKey.hash; + result ^= _PEMCertChain.hash; + result ^= _hostNameOverride.hash; + result ^= _transportType; + result ^= [_logContext hash]; + result ^= _channelPoolDomain.hash; + result ^= _channelID; + + return result; +} + @end @implementation GRPCMutableCallOptions diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 995212fdb6..4fae7d57ca 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -153,24 +153,7 @@ extern const char *kCFStreamVarName; - (NSUInteger)hash { NSUInteger result = 0; result ^= _host.hash; - result ^= _callOptions.userAgentPrefix.hash; - result ^= _callOptions.responseSizeLimit; - result ^= _callOptions.compressAlgorithm; - result ^= _callOptions.enableRetry; - result ^= (unsigned int)(_callOptions.keepaliveInterval * 1000); - result ^= (unsigned int)(_callOptions.keepaliveTimeout * 1000); - result ^= (unsigned int)(_callOptions.connectMinTimeout * 1000); - result ^= (unsigned int)(_callOptions.connectInitialBackoff * 1000); - result ^= (unsigned int)(_callOptions.connectMaxBackoff * 1000); - result ^= _callOptions.additionalChannelArgs.hash; - result ^= _callOptions.PEMRootCertificates.hash; - result ^= _callOptions.PEMPrivateKey.hash; - result ^= _callOptions.PEMCertChain.hash; - result ^= _callOptions.hostNameOverride.hash; - result ^= _callOptions.transportType; - result ^= [_callOptions.logContext hash]; - result ^= _callOptions.channelPoolDomain.hash; - result ^= _callOptions.channelID; + result ^= _callOptions.channelOptionsHash; return result; } -- cgit v1.2.3 From 34e4db810fcf08f51ee5104561426fc736308216 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 18:04:42 -0700 Subject: Take advantage of nil messaging --- src/objective-c/GRPCClient/private/GRPCChannel.m | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 9e7e1ea1fc..5e0b37c1b8 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -84,10 +84,8 @@ NSTimeInterval kChannelDestroyDelay = 30; - (void)refChannel { if (!_disconnected) { _refCount++; - if (_timer) { - [_timer invalidate]; - _timer = nil; - } + [_timer invalidate]; + _timer = nil; } } @@ -96,9 +94,7 @@ NSTimeInterval kChannelDestroyDelay = 30; if (!_disconnected) { _refCount--; if (_refCount == 0) { - if (_timer) { - [_timer invalidate]; - } + [_timer invalidate]; _timer = [NSTimer scheduledTimerWithTimeInterval:self->_destroyDelay target:self selector:@selector(timerFire:) @@ -111,10 +107,8 @@ NSTimeInterval kChannelDestroyDelay = 30; // This function is protected by channel dispatch queue. - (void)disconnect { if (!_disconnected) { - if (self->_timer != nil) { - [self->_timer invalidate]; - self->_timer = nil; - } + [_timer invalidate]; + _timer = nil; _disconnected = YES; // Break retain loop _destroyChannelCallback = nil; -- cgit v1.2.3 From be4ab30899f6ae91e07f02c33297ca462f778296 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 17 Oct 2018 18:05:22 -0700 Subject: Remove dereferencing --- src/objective-c/GRPCClient/private/GRPCChannel.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 5e0b37c1b8..a17cc253fe 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -95,7 +95,7 @@ NSTimeInterval kChannelDestroyDelay = 30; _refCount--; if (_refCount == 0) { [_timer invalidate]; - _timer = [NSTimer scheduledTimerWithTimeInterval:self->_destroyDelay + _timer = [NSTimer scheduledTimerWithTimeInterval:_destroyDelay target:self selector:@selector(timerFire:) userInfo:nil -- cgit v1.2.3 From 67a4eb6623d0870992051d0280b78dd7a2b2c0ff Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 09:53:41 -0700 Subject: Lock GRPCCall in GRPCAuthorizatioProtocol --- src/objective-c/GRPCClient/GRPCCall.m | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 5ffdfbaa89..68f0f8892d 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -461,10 +461,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)cancel { - if (!self.isWaitingForToken) { - [self cancelCall]; - } else { - self.isWaitingForToken = NO; + @synchronized (self) { + if (!self.isWaitingForToken) { + [self cancelCall]; + } else { + self.isWaitingForToken = NO; + } } [self maybeFinishWithError:[NSError @@ -779,14 +781,18 @@ const char *kCFStreamVarName = "grpc_cfstream"; _callOptions = callOptions; } if (_callOptions.authTokenProvider != nil) { - self.isWaitingForToken = YES; + @synchronized (self) { + self.isWaitingForToken = YES; + } [self.tokenProvider getTokenWithHandler:^(NSString *token) { - if (self.isWaitingForToken) { - if (token) { - self->_fetchedOauth2AccessToken = [token copy]; + @synchronized (self) { + if (self.isWaitingForToken) { + if (token) { + self->_fetchedOauth2AccessToken = [token copy]; + } + [self startCallWithWriteable:writeable]; + self.isWaitingForToken = NO; } - [self startCallWithWriteable:writeable]; - self.isWaitingForToken = NO; } }]; } else { -- cgit v1.2.3 From ac211b4214b9a5bbc00631b61af396557837b9fb Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 10:39:48 -0700 Subject: Use dispatch_after for delayed destroy of channel --- src/objective-c/GRPCClient/private/GRPCChannel.m | 87 +++++++++++++----------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index a17cc253fe..a91949684c 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -57,14 +57,13 @@ NSTimeInterval kChannelDestroyDelay = 30; @implementation GRPCChannelRef { NSTimeInterval _destroyDelay; - // We use dispatch queue for this purpose since timer invalidation must happen on the same - // thread which issued the timer. - dispatch_queue_t _dispatchQueue; void (^_destroyChannelCallback)(); NSUInteger _refCount; - NSTimer *_timer; BOOL _disconnected; + dispatch_queue_t _dispatchQueue; + dispatch_queue_t _timerQueue; + NSDate *_lastDispatch; } - (instancetype)initWithDestroyDelay:(NSTimeInterval)destroyDelay @@ -74,57 +73,65 @@ NSTimeInterval kChannelDestroyDelay = 30; _destroyChannelCallback = destroyChannelCallback; _refCount = 1; - _timer = nil; _disconnected = NO; + if (@available(iOS 8.0, *)) { + _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + _timerQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_DEFAULT, -1)); + } else { + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + _timerQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); + } + _lastDispatch = nil; } return self; } -// This function is protected by channel dispatch queue. - (void)refChannel { - if (!_disconnected) { - _refCount++; - [_timer invalidate]; - _timer = nil; - } + dispatch_async(_dispatchQueue, ^{ + if (!self->_disconnected) { + self->_refCount++; + self->_lastDispatch = nil; + } + }); } -// This function is protected by channel dispatch queue. - (void)unrefChannel { - if (!_disconnected) { - _refCount--; - if (_refCount == 0) { - [_timer invalidate]; - _timer = [NSTimer scheduledTimerWithTimeInterval:_destroyDelay - target:self - selector:@selector(timerFire:) - userInfo:nil - repeats:NO]; + dispatch_async(_dispatchQueue, ^{ + if (!self->_disconnected) { + self->_refCount--; + if (self->_refCount == 0) { + self->_lastDispatch = [NSDate date]; + dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)kChannelDestroyDelay * 1e9); + dispatch_after(delay, self->_timerQueue, ^{ + [self timerFire]; + }); + } } - } + }); } -// This function is protected by channel dispatch queue. - (void)disconnect { - if (!_disconnected) { - [_timer invalidate]; - _timer = nil; - _disconnected = YES; - // Break retain loop - _destroyChannelCallback = nil; - } + dispatch_async(_dispatchQueue, ^{ + if (!self->_disconnected) { + self->_lastDispatch = nil; + self->_disconnected = YES; + // Break retain loop + self->_destroyChannelCallback = nil; + } + }); } -// This function is protected by channel dispatch queue. -- (void)timerFire:(NSTimer *)timer { - if (_disconnected || _timer == nil || _timer != timer) { - return; - } - _timer = nil; - _destroyChannelCallback(); - // Break retain loop - _destroyChannelCallback = nil; - _disconnected = YES; +- (void)timerFire { + dispatch_async(_dispatchQueue, ^{ + if (self->_disconnected || self->_lastDispatch == nil || -[self->_lastDispatch timeIntervalSinceNow] < -kChannelDestroyDelay) { + return; + } + self->_lastDispatch = nil; + self->_disconnected = YES; + self->_destroyChannelCallback(); + // Break retain loop + self->_destroyChannelCallback = nil; + }); } @end -- cgit v1.2.3 From 7871fedfd6e594ac5935d2018b9680e18979991c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 11:13:22 -0700 Subject: always unregister observer --- src/objective-c/GRPCClient/GRPCCall.m | 6 +----- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 68f0f8892d..a142c669db 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -445,11 +445,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; [_responseWriteable enqueueSuccessfulCompletion]; } - // Connectivity monitor is not required for CFStream - char *enableCFStream = getenv(kCFStreamVarName); - if (enableCFStream == nil || enableCFStream[0] != '1') { - [GRPCConnectivityMonitor unregisterObserver:self]; - } + [GRPCConnectivityMonitor unregisterObserver:self]; // If the call isn't retained anywhere else, it can be deallocated now. _retainSelf = nil; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 4fae7d57ca..5707e7f950 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -187,11 +187,7 @@ extern const char *kCFStreamVarName; } - (void)dealloc { - // Connectivity monitor is not required for CFStream - char *enableCFStream = getenv(kCFStreamVarName); - if (enableCFStream == nil || enableCFStream[0] != '1') { - [GRPCConnectivityMonitor unregisterObserver:self]; - } + [GRPCConnectivityMonitor unregisterObserver:self]; } - (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration { -- cgit v1.2.3 From 4af17518c023cd32bc98c796d6f99e4f4978f49a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 11:42:41 -0700 Subject: Use simple locking in GRPCChannelPool --- .../GRPCClient/private/GRPCChannelPool.m | 37 ++++++++++------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 5707e7f950..bfc624eb4e 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -164,18 +164,11 @@ extern const char *kCFStreamVarName; @implementation GRPCChannelPool { NSMutableDictionary *_channelPool; - // Dedicated queue for timer - dispatch_queue_t _dispatchQueue; } - (instancetype)init { if ((self = [super init])) { _channelPool = [NSMutableDictionary dictionary]; - if (@available(iOS 8.0, *)) { - _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); - } else { - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } // Connectivity monitor is not required for CFStream char *enableCFStream = getenv(kCFStreamVarName); @@ -192,37 +185,39 @@ extern const char *kCFStreamVarName; - (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration { __block GRPCChannel *channel; - dispatch_sync(_dispatchQueue, ^{ - if ([self->_channelPool objectForKey:configuration]) { - channel = self->_channelPool[configuration]; + @synchronized(self) { + if ([_channelPool objectForKey:configuration]) { + channel = _channelPool[configuration]; [channel unmanagedCallRef]; } else { channel = [GRPCChannel createChannelWithConfiguration:configuration]; - self->_channelPool[configuration] = channel; + if (channel != nil) { + _channelPool[configuration] = channel; + } } - }); + } return channel; } - (void)removeChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { - dispatch_async(_dispatchQueue, ^{ + @synchronized(self) { [self->_channelPool removeObjectForKey:configuration]; - }); + } } - (void)removeAllChannels { - dispatch_sync(_dispatchQueue, ^{ - self->_channelPool = [NSMutableDictionary dictionary]; - }); + @synchronized(self) { + _channelPool = [NSMutableDictionary dictionary]; + } } - (void)removeAndCloseAllChannels { - dispatch_sync(_dispatchQueue, ^{ - [self->_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannel * _Nonnull obj, BOOL * _Nonnull stop) { + @synchronized(self) { + [_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannel * _Nonnull obj, BOOL * _Nonnull stop) { [obj disconnect]; }]; - self->_channelPool = [NSMutableDictionary dictionary]; - }); + _channelPool = [NSMutableDictionary dictionary]; + } } - (void)connectivityChange:(NSNotification *)note { -- cgit v1.2.3 From 3bdf794bd031162913f533a2a9535f4066a41abd Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 11:50:00 -0700 Subject: Handle channel nil case --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index a142c669db..0facf97e09 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -720,7 +720,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeUnavailable userInfo:@{ - NSLocalizedDescriptionKey : @"Failed to create call from channel." + NSLocalizedDescriptionKey : @"Failed to create call or channel." }]]; return; } -- cgit v1.2.3 From a0f83554bbe47d9d99d6e3146a8ec7ba3a129b63 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 12:11:29 -0700 Subject: remove channel from pool with pointer rather than config --- src/objective-c/GRPCClient/private/GRPCChannel.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 4 ++-- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 8 ++++++-- src/objective-c/tests/ChannelTests/ChannelPoolTest.m | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index a91949684c..2420988f42 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -204,7 +204,7 @@ NSTimeInterval kChannelDestroyDelay = 30; if (self->_unmanagedChannel) { grpc_channel_destroy(self->_unmanagedChannel); self->_unmanagedChannel = nil; - [gChannelPool removeChannelWithConfiguration:self->_configuration]; + [gChannelPool removeChannel:self]; } }); } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index bd1350c15d..e9c2ef2bd1 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -55,8 +55,8 @@ NS_ASSUME_NONNULL_BEGIN */ - (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration; -/** Remove a channel with particular configuration. */ -- (void)removeChannelWithConfiguration:(GRPCChannelConfiguration *)configuration; +/** Remove a channel from the pool. */ +- (void)removeChannel:(GRPCChannel *)channel; /** Clear all channels in the pool. */ - (void)removeAllChannels; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index bfc624eb4e..b5b3ff60ef 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -199,9 +199,13 @@ extern const char *kCFStreamVarName; return channel; } -- (void)removeChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { +- (void)removeChannel:(GRPCChannel *)channel { @synchronized(self) { - [self->_channelPool removeObjectForKey:configuration]; + [_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannel * _Nonnull obj, BOOL * _Nonnull stop) { + if (obj == channel) { + [self->_channelPool removeObjectForKey:key]; + } + }]; } } diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index b195b747a1..db64ac6339 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -59,7 +59,7 @@ NSString *kDummyHost = @"dummy.host"; GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; - [pool removeChannelWithConfiguration:config1]; + [pool removeChannel:channel1]; GRPCChannel *channel2 = [pool channelWithConfiguration:config1]; XCTAssertNotEqual(channel1, channel2); -- cgit v1.2.3 From 1a88be4edfba35732236956e6e835ecd5c9de13d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 13:56:03 -0700 Subject: Prefix functions in ChannelArgsUtil --- src/objective-c/GRPCClient/private/ChannelArgsUtil.h | 4 ++-- src/objective-c/GRPCClient/private/ChannelArgsUtil.m | 4 ++-- src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m | 4 ++-- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.h b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h index d9d6933c6b..d0be484910 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.h +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h @@ -20,6 +20,6 @@ #include -void FreeChannelArgs(grpc_channel_args* channel_args); +void GRPCFreeChannelArgs(grpc_channel_args* channel_args); -grpc_channel_args* BuildChannelArgs(NSDictionary* dictionary); +grpc_channel_args* GRPCBuildChannelArgs(NSDictionary* dictionary); diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m index b26fb12d59..8669f79992 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -39,7 +39,7 @@ static int cmp_pointer_arg(void *p, void *q) { return p == q; } static const grpc_arg_pointer_vtable objc_arg_vtable = {copy_pointer_arg, destroy_pointer_arg, cmp_pointer_arg}; -void FreeChannelArgs(grpc_channel_args *channel_args) { +void GRPCFreeChannelArgs(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); @@ -58,7 +58,7 @@ void FreeChannelArgs(grpc_channel_args *channel_args) { * 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) { +grpc_channel_args *GRPCBuildChannelArgs(NSDictionary *dictionary) { if (!dictionary) { return NULL; } diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m index d969b887b4..5773f2d9af 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -36,10 +36,10 @@ NS_ASSUME_NONNULL_BEGIN - (nullable grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(nullable NSDictionary *)args { - grpc_channel_args *coreChannelArgs = BuildChannelArgs([args copy]); + grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); - FreeChannelArgs(coreChannelArgs); + GRPCFreeChannelArgs(coreChannelArgs); return unmanagedChannel; } diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 277823c4e3..8a00d080a1 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -111,10 +111,10 @@ NS_ASSUME_NONNULL_BEGIN - (nullable grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(nullable NSDictionary *)args { - grpc_channel_args *coreChannelArgs = BuildChannelArgs([args copy]); + grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); - FreeChannelArgs(coreChannelArgs); + GRPCFreeChannelArgs(coreChannelArgs); return unmanagedChannel; } -- cgit v1.2.3 From e114983643479d20e44536cb704f5738cb848329 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 13:57:53 -0700 Subject: NULL return for non-id type --- src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index 00b388ebbe..7067578467 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -84,7 +84,7 @@ NS_ASSUME_NONNULL_BEGIN channelArgs:(nullable NSDictionary *)args { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; - return nil; + return NULL; } @end -- cgit v1.2.3 From 31de6d67e7557208b9d1e8c37300fb3f6b45a47d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 14:00:07 -0700 Subject: Make GRPCHost.callOptions immutable --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/GRPCClient/private/GRPCHost.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 0facf97e09..3f77aaafb3 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -751,7 +751,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; GRPCMutableCallOptions *callOptions; if ([GRPCHost isHostConfigured:_host]) { GRPCHost *hostConfig = [GRPCHost hostWithAddress:_host]; - callOptions = hostConfig.callOptions; + callOptions = [hostConfig.callOptions mutableCopy]; } else { callOptions = [[GRPCMutableCallOptions alloc] init]; } diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h index 32d3585351..e321363bcb 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.h +++ b/src/objective-c/GRPCClient/private/GRPCHost.h @@ -66,7 +66,7 @@ struct grpc_channel_credentials; @property(atomic, readwrite) GRPCTransportType transportType; -@property(readonly) GRPCMutableCallOptions *callOptions; +@property(readonly) GRPCCallOptions *callOptions; + (BOOL)isHostConfigured:(NSString *)address; -- cgit v1.2.3 From d92c62fcde8559393aee346e5518faecb6f1301b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 15:22:16 -0700 Subject: Enable Cronet with old API --- src/objective-c/GRPCClient/private/GRPCHost.m | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 7c31b10636..6bb5996a1b 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -113,7 +113,21 @@ static NSMutableDictionary *kHostCache; options.PEMPrivateKey = _PEMPrivateKey; options.PEMCertChain = _pemCertChain; options.hostNameOverride = _hostNameOverride; - options.transportType = _transportType; +#ifdef GRPC_COMPILE_WITH_CRONET + // By old API logic, insecure channel precedes Cronet channel; Cronet channel preceeds default + // channel. + if ([GRPCCall isUsingCronet]) { + if (_transportType == GRPCTransportTypeInsecure) { + options.transportType = GRPCTransportTypeInsecure; + } else { + NSAssert(_transportType == GRPCTransportTypeDefault, @"Invalid transport type"); + options.transportType = GRPCTransportTypeCronet; + } + } else +#endif + { + options.transportType = _transportType; + } options.logContext = _logContext; return options; -- cgit v1.2.3 From 1084f49c310b62ff5a06fa5f6c262f813dce75a5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 15:22:38 -0700 Subject: rename kHostCache->gHostCache --- src/objective-c/GRPCClient/private/GRPCHost.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 6bb5996a1b..c1992b84e9 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN -static NSMutableDictionary *kHostCache; +static NSMutableDictionary *gHostCache; @implementation GRPCHost { NSString *_PEMRootCertificates; @@ -65,10 +65,10 @@ static NSMutableDictionary *kHostCache; // Look up the GRPCHost in the cache. static dispatch_once_t cacheInitialization; dispatch_once(&cacheInitialization, ^{ - kHostCache = [NSMutableDictionary dictionary]; + gHostCache = [NSMutableDictionary dictionary]; }); - @synchronized(kHostCache) { - GRPCHost *cachedHost = kHostCache[address]; + @synchronized(gHostCache) { + GRPCHost *cachedHost = gHostCache[address]; if (cachedHost) { return cachedHost; } @@ -76,15 +76,15 @@ static NSMutableDictionary *kHostCache; if ((self = [super init])) { _address = address; _retryEnabled = YES; - kHostCache[address] = self; + gHostCache[address] = self; } } return self; } + (void)resetAllHostSettings { - @synchronized(kHostCache) { - kHostCache = [NSMutableDictionary dictionary]; + @synchronized(gHostCache) { + gHostCache = [NSMutableDictionary dictionary]; } } @@ -140,8 +140,8 @@ static NSMutableDictionary *kHostCache; address = [hostURL.host stringByAppendingString:@":443"]; } __block GRPCHost *cachedHost; - @synchronized (kHostCache) { - cachedHost = kHostCache[address]; + @synchronized (gHostCache) { + cachedHost = gHostCache[address]; } return (cachedHost != nil); } -- cgit v1.2.3 From b9e522420741024e05f8ef3ccde7fbeeaaea2234 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 15:28:15 -0700 Subject: more copy settings --- src/objective-c/GRPCClient/private/GRPCHost.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index c1992b84e9..032b274ffc 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -92,9 +92,9 @@ static NSMutableDictionary *gHostCache; withPrivateKey:(nullable NSString *)pemPrivateKey withCertChain:(nullable NSString *)pemCertChain error:(NSError **)errorPtr { - _PEMRootCertificates = pemRootCerts; - _PEMPrivateKey = pemPrivateKey; - _pemCertChain = pemCertChain; + _PEMRootCertificates = [pemRootCerts copy]; + _PEMPrivateKey = [pemPrivateKey copy]; + _pemCertChain = [pemCertChain copy]; return YES; } -- cgit v1.2.3 From 4201ad1681064d591f6a47fa5b3c6f824cb7cecb Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 16:05:18 -0700 Subject: add callOptionsForHost: to GRPCHost --- src/objective-c/GRPCClient/GRPCCall.m | 8 ++------ src/objective-c/GRPCClient/private/GRPCHost.h | 4 +--- src/objective-c/GRPCClient/private/GRPCHost.m | 22 ++++++++++++++-------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 3f77aaafb3..399206a346 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -749,12 +749,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (_callOptions == nil) { GRPCMutableCallOptions *callOptions; - if ([GRPCHost isHostConfigured:_host]) { - GRPCHost *hostConfig = [GRPCHost hostWithAddress:_host]; - callOptions = [hostConfig.callOptions mutableCopy]; - } else { - callOptions = [[GRPCMutableCallOptions alloc] init]; - } + + callOptions = [[GRPCHost callOptionsForHost:_host] mutableCopy]; if (_serverName.length != 0) { callOptions.serverAuthority = _serverName; } diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h index e321363bcb..f1d5719642 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.h +++ b/src/objective-c/GRPCClient/private/GRPCHost.h @@ -66,9 +66,7 @@ struct grpc_channel_credentials; @property(atomic, readwrite) GRPCTransportType transportType; -@property(readonly) GRPCCallOptions *callOptions; - -+ (BOOL)isHostConfigured:(NSString *)address; ++ (GRPCCallOptions *)callOptionsForHost:(NSString *)host; @end diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 032b274ffc..5fe022a1ba 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -133,17 +133,23 @@ static NSMutableDictionary *gHostCache; return options; } -+ (BOOL)isHostConfigured:(NSString *)address { ++ (GRPCCallOptions *)callOptionsForHost:(NSString *)host { // TODO (mxyan): Remove when old API is deprecated - NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]]; - if (hostURL.host && !hostURL.port) { - address = [hostURL.host stringByAppendingString:@":443"]; + NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:host]]; + if (hostURL.host && hostURL.port == nil) { + host = [hostURL.host stringByAppendingString:@":443"]; + } + + __block GRPCCallOptions *callOptions = nil; + @synchronized(gHostCache) { + if ([gHostCache objectForKey:host]) { + callOptions = [gHostCache[host] callOptions]; + } } - __block GRPCHost *cachedHost; - @synchronized (gHostCache) { - cachedHost = gHostCache[address]; + if (callOptions == nil) { + callOptions = [[GRPCCallOptions alloc] init]; } - return (cachedHost != nil); + return callOptions; } @end -- cgit v1.2.3 From f00be37dd19842e2e2f906b71d0525c2dc913378 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 16:07:09 -0700 Subject: Spell out 'certificates' rather than 'certs' --- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 8 ++++---- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h | 8 ++++---- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index b5b3ff60ef..5d53cb2e99 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -52,10 +52,10 @@ extern const char *kCFStreamVarName; #ifdef GRPC_COMPILE_WITH_CRONET if (![GRPCCall isUsingCronet]) { #endif - factory = [GRPCSecureChannelFactory factoryWithPEMRootCerts:_callOptions.PEMRootCertificates - privateKey:_callOptions.PEMPrivateKey - certChain:_callOptions.PEMCertChain - error:&error]; + factory = [GRPCSecureChannelFactory factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates + privateKey:_callOptions.PEMPrivateKey + certChain:_callOptions.PEMCertChain + error:&error]; if (factory == nil) { NSLog(@"Error creating secure channel factory: %@", error); } diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h index 82af0dc3e6..588239b706 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h @@ -23,10 +23,10 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCSecureChannelFactory : NSObject -+ (nullable instancetype)factoryWithPEMRootCerts:(nullable NSString *)rootCerts - privateKey:(nullable NSString *)privateKey - certChain:(nullable NSString *)certChain - error:(NSError **)errorPtr; ++ (nullable instancetype)factoryWithPEMRootCertificates:(nullable NSString *)rootCerts + privateKey:(nullable NSString *)privateKey + certChain:(nullable NSString *)certChain + error:(NSError **)errorPtr; - (nullable grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(nullable NSDictionary *)args; diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 8a00d080a1..b116c16ec0 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -29,10 +29,10 @@ NS_ASSUME_NONNULL_BEGIN grpc_channel_credentials *_channelCreds; } -+ (nullable instancetype)factoryWithPEMRootCerts:(nullable NSString *)rootCerts - privateKey:(nullable NSString *)privateKey - certChain:(nullable NSString *)certChain - error:(NSError **)errorPtr { ++ (nullable instancetype)factoryWithPEMRootCertificates:(nullable NSString *)rootCerts + privateKey:(nullable NSString *)privateKey + certChain:(nullable NSString *)certChain + error:(NSError **)errorPtr { return [[self alloc] initWithPEMRootCerts:rootCerts privateKey:privateKey certChain:certChain -- cgit v1.2.3 From 6ae2ea643d89f7b2e7839f9016a61361ce92b5d5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 16:32:42 -0700 Subject: obj.class->[obj class] --- .../GRPCClient/private/GRPCRequestHeaders.m | 4 +- .../GRPCClient/private/GRPCSecureChannelFactory.m | 2 +- src/objective-c/ProtoRPC/ProtoRPC.m | 2 +- src/objective-c/tests/InteropTests.m | 62 +++++++++++----------- src/objective-c/tests/InteropTestsLocalSSL.m | 4 +- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m index fa4f022ff0..5f117f0607 100644 --- a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m +++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m @@ -36,7 +36,7 @@ static void CheckIsNonNilASCII(NSString *name, NSString *value) { // Precondition: key isn't nil. static void CheckKeyValuePairIsValid(NSString *key, id value) { if ([key hasSuffix:@"-bin"]) { - if (![value isKindOfClass:NSData.class]) { + if (![value isKindOfClass:[NSData class]]) { [NSException raise:NSInvalidArgumentException format: @"Expected NSData value for header %@ ending in \"-bin\", " @@ -44,7 +44,7 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) { key, value]; } } else { - if (![value isKindOfClass:NSString.class]) { + if (![value isKindOfClass:[NSString class]]) { [NSException raise:NSInvalidArgumentException format: @"Expected NSString value for header %@ not ending in \"-bin\", " diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index b116c16ec0..13bca6c40d 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -57,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN 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]; + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"]; NSError *error; // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 9fb398408b..d3005e30a5 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -252,7 +252,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } // A writer that serializes the proto messages to send. GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) { - if (![proto isKindOfClass:GPBMessage.class]) { + if (![proto isKindOfClass:[GPBMessage class]]) { [NSException raise:NSInvalidArgumentException format:@"Request must be a proto message: %@", proto]; } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 11d4b95663..ca49b5fc39 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -173,11 +173,11 @@ BOOL isRemoteInteropTest(NSString *host) { [GRPCCall resetHostSettings]; - _service = self.class.host ? [RMTTestService serviceWithHost:self.class.host] : nil; + _service = [[self class] host] ? [RMTTestService serviceWithHost:[[self class] host]] : nil; } - (void)testEmptyUnaryRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"]; GPBEmpty *request = [GPBEmpty message]; @@ -196,14 +196,14 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testEmptyUnaryRPCWithV2API { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"]; GPBEmpty *request = [GPBEmpty message]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.transportType = self.class.transportType; - options.PEMRootCertificates = self.class.PEMRootCertificates; - options.hostNameOverride = self.class.hostNameOverride; + options.transportType = [[self class] transportType]; + options.PEMRootCertificates = [[self class] PEMRootCertificates]; + options.hostNameOverride = [[self class] hostNameOverride]; [_service emptyCallWithMessage:request @@ -223,7 +223,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testLargeUnaryRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -247,7 +247,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testPacketCoalescing { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -286,7 +286,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)test4MBResponsesAreAccepted { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -304,7 +304,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testResponsesOverMaxSizeFailWithActionableMessage { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -330,7 +330,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testResponsesOver4MBAreAcceptedIfOptedIn { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"HigherResponseSizeLimit"]; @@ -338,7 +338,7 @@ BOOL isRemoteInteropTest(NSString *host) { const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB request.responseSize = kPayloadSize; - [GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:self.class.host]; + [GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:[[self class] host]]; [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { @@ -351,7 +351,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testClientStreamingRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ClientStreaming"]; RMTStreamingInputCallRequest *request1 = [RMTStreamingInputCallRequest message]; @@ -386,7 +386,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testServerStreamingRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ServerStreaming"]; NSArray *expectedSizes = @[ @31415, @9, @2653, @58979 ]; @@ -425,7 +425,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testPingPongRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"]; NSArray *requests = @[ @27182, @8, @1828, @45904 ]; @@ -472,7 +472,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testPingPongRPCWithV2API { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"]; NSArray *requests = @[ @27182, @8, @1828, @45904 ]; @@ -483,9 +483,9 @@ BOOL isRemoteInteropTest(NSString *host) { id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.transportType = self.class.transportType; - options.PEMRootCertificates = self.class.PEMRootCertificates; - options.hostNameOverride = self.class.hostNameOverride; + options.transportType = [[self class] transportType ]; + options.PEMRootCertificates = [[self class] PEMRootCertificates]; + options.hostNameOverride = [[self class] hostNameOverride]; __block GRPCStreamingProtoCall *call = [_service fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] @@ -523,7 +523,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testEmptyStreamRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"]; [_service fullDuplexCallWithRequestsWriter:[GRXWriter emptyWriter] eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response, @@ -536,7 +536,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testCancelAfterBeginRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBegin"]; // A buffered pipe to which we never write any value acts as a writer that just hangs. @@ -561,7 +561,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testCancelAfterBeginRPCWithV2API { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBegin"]; // A buffered pipe to which we never write any value acts as a writer that just hangs. @@ -583,7 +583,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testCancelAfterFirstResponseRPC { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterFirstResponse"]; @@ -619,7 +619,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testCancelAfterFirstResponseRPCWithV2API { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *completionExpectation = [self expectationWithDescription:@"Call completed."]; __weak XCTestExpectation *responseExpectation = @@ -630,7 +630,7 @@ BOOL isRemoteInteropTest(NSString *host) { GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.transportType = self.class.transportType; options.PEMRootCertificates = self.class.PEMRootCertificates; - options.hostNameOverride = self.class.hostNameOverride; + options.hostNameOverride = [[self class] hostNameOverride]; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 requestedResponseSize:@31415]; @@ -656,7 +656,7 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)testRPCAfterClosingOpenConnections { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC after closing connection"]; @@ -688,10 +688,10 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testCompressedUnaryRPC { // This test needs to be disabled for remote test because interop server grpc-test // does not support compression. - if (isRemoteInteropTest(self.class.host)) { + if (isRemoteInteropTest([[self class] host])) { return; } - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -699,7 +699,7 @@ BOOL isRemoteInteropTest(NSString *host) { request.responseSize = 314159; request.payload.body = [NSMutableData dataWithLength:271828]; request.expectCompressed.value = YES; - [GRPCCall setDefaultCompressMethod:GRPCCompressGzip forhost:self.class.host]; + [GRPCCall setDefaultCompressMethod:GRPCCompressGzip forhost:[[self class] host]]; [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { @@ -718,10 +718,10 @@ BOOL isRemoteInteropTest(NSString *host) { #ifndef GRPC_COMPILE_WITH_CRONET - (void)testKeepalive { - XCTAssertNotNil(self.class.host); + XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Keepalive"]; - [GRPCCall setKeepaliveWithInterval:1500 timeout:0 forHost:self.class.host]; + [GRPCCall setKeepaliveWithInterval:1500 timeout:0 forHost:[[self class] host]]; NSArray *requests = @[ @27182, @8 ]; NSArray *responses = @[ @31415, @9 ]; diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m index 759a080380..e8222f602f 100644 --- a/src/objective-c/tests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTestsLocalSSL.m @@ -41,7 +41,7 @@ static int32_t kLocalInteropServerOverhead = 10; } + (NSString *)PEMRootCertificates { - NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"]; NSError *error; @@ -64,7 +64,7 @@ static int32_t kLocalInteropServerOverhead = 10; [super setUp]; // Register test server certificates and name. - NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"]; [GRPCCall useTestCertsPath:certsPath testName:@"foo.test.google.fr" forHost:kLocalSSLHost]; -- cgit v1.2.3 From 4264ea2b55f46c1904fc179fb0db7b733b8c3e4b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 18 Oct 2018 17:04:03 -0700 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.h | 10 +- src/objective-c/GRPCClient/GRPCCall.m | 34 ++++--- src/objective-c/GRPCClient/GRPCCallOptions.m | 26 +++--- src/objective-c/GRPCClient/private/GRPCChannel.m | 36 +++++--- .../GRPCClient/private/GRPCChannelPool.m | 35 ++++--- src/objective-c/ProtoRPC/ProtoRPC.h | 6 +- src/objective-c/ProtoRPC/ProtoRPC.m | 10 +- src/objective-c/ProtoRPC/ProtoService.h | 13 +-- .../tests/ChannelTests/ChannelPoolTest.m | 35 +++---- src/objective-c/tests/GRPCClientTests.m | 101 ++++++++++----------- src/objective-c/tests/InteropTests.m | 2 +- 11 files changed, 161 insertions(+), 147 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 6adecec144..bd43a0a384 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -149,7 +149,7 @@ extern id const kGRPCHeadersKey; extern id const kGRPCTrailersKey; /** An object can implement this protocol to receive responses from server from a call. */ -@protocol GRPCResponseHandler +@protocol GRPCResponseHandler @optional @@ -188,10 +188,12 @@ extern id const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** Initialize with all properties. */ -- (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + safety:(GRPCCallSafety)safety NS_DESIGNATED_INITIALIZER; /** The host serving the RPC service. */ @property(copy, readonly) NSString *host; @@ -214,7 +216,7 @@ extern id const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** * Designated initializer for a call. diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 399206a346..bd4b4e10f0 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -28,8 +28,8 @@ #include #import "GRPCCallOptions.h" -#import "private/GRPCHost.h" #import "private/GRPCConnectivityMonitor.h" +#import "private/GRPCHost.h" #import "private/GRPCRequestHeaders.h" #import "private/GRPCWrappedCall.h" #import "private/NSData+GRPC.h" @@ -115,7 +115,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; _initialMetadataPublished = NO; _pipe = [GRXBufferedPipe pipe]; if (@available(iOS 8.0, *)) { - _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + _dispatchQueue = dispatch_queue_create( + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); } else { // Fallback on earlier versions _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); @@ -129,7 +131,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler { - return [self initWithRequestOptions:requestOptions responseHandler:responseHandler callOptions:nil]; + return + [self initWithRequestOptions:requestOptions responseHandler:responseHandler callOptions:nil]; } - (void)start { @@ -210,9 +213,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; error:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeCancelled userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; } }); @@ -255,13 +258,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; } } -- (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata - error:(NSError *)error { +- (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { id handler = _handler; NSDictionary *trailers = _call.responseTrailers; if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:trailers error:error]; + [handler closedWithTrailingMetadata:trailers error:error]; }); } } @@ -388,7 +390,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { if (host.length == 0 || path.length == 0) { - [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil or empty."]; + [NSException raise:NSInvalidArgumentException + format:@"Neither host nor path can be nil or empty."]; } if (safety > GRPCCallSafetyCacheableRequest) { [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; @@ -457,7 +460,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)cancel { - @synchronized (self) { + @synchronized(self) { if (!self.isWaitingForToken) { [self cancelCall]; } else { @@ -720,8 +723,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeUnavailable userInfo:@{ - NSLocalizedDescriptionKey : @"Failed to create call or channel." - }]]; + NSLocalizedDescriptionKey : + @"Failed to create call or channel." + }]]; return; } @@ -773,11 +777,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; _callOptions = callOptions; } if (_callOptions.authTokenProvider != nil) { - @synchronized (self) { + @synchronized(self) { self.isWaitingForToken = YES; } [self.tokenProvider getTokenWithHandler:^(NSString *token) { - @synchronized (self) { + @synchronized(self) { if (self.isWaitingForToken) { if (token) { self->_fetchedOauth2AccessToken = [token copy]; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 8d2b84b748..37ed3ebd1d 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -110,7 +110,7 @@ static NSUInteger kDefaultChannelID = 0; connectInitialBackoff:kDefaultConnectInitialBackoff connectMaxBackoff:kDefaultConnectMaxBackoff additionalChannelArgs:kDefaultAdditionalChannelArgs - PEMRootCertificates:kDefaultPEMRootCertificates + PEMRootCertificates:kDefaultPEMRootCertificates PEMPrivateKey:kDefaultPEMPrivateKey PEMCertChain:kDefaultPEMCertChain transportType:kDefaultTransportType @@ -135,7 +135,7 @@ static NSUInteger kDefaultChannelID = 0; connectInitialBackoff:(NSTimeInterval)connectInitialBackoff connectMaxBackoff:(NSTimeInterval)connectMaxBackoff additionalChannelArgs:(NSDictionary *)additionalChannelArgs - PEMRootCertificates:(NSString *)PEMRootCertificates + PEMRootCertificates:(NSString *)PEMRootCertificates PEMPrivateKey:(NSString *)PEMPrivateKey PEMCertChain:(NSString *)PEMCertChain transportType:(GRPCTransportType)transportType @@ -158,7 +158,8 @@ static NSUInteger kDefaultChannelID = 0; _connectMinTimeout = connectMinTimeout; _connectInitialBackoff = connectInitialBackoff; _connectMaxBackoff = connectMaxBackoff; - _additionalChannelArgs = [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; + _additionalChannelArgs = + [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; _PEMRootCertificates = [PEMRootCertificates copy]; _PEMPrivateKey = [PEMPrivateKey copy]; _PEMCertChain = [PEMCertChain copy]; @@ -188,7 +189,7 @@ static NSUInteger kDefaultChannelID = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:_additionalChannelArgs - PEMRootCertificates:_PEMRootCertificates + PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey PEMCertChain:_PEMCertChain transportType:_transportType @@ -216,7 +217,7 @@ static NSUInteger kDefaultChannelID = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:[_additionalChannelArgs copy] - PEMRootCertificates:_PEMRootCertificates + PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey PEMCertChain:_PEMCertChain transportType:_transportType @@ -240,8 +241,7 @@ static NSUInteger kDefaultChannelID = 0; if (!(callOptions.connectInitialBackoff == _connectInitialBackoff)) return NO; if (!(callOptions.connectMaxBackoff == _connectMaxBackoff)) return NO; if (!(callOptions.additionalChannelArgs == _additionalChannelArgs || - [callOptions.additionalChannelArgs - isEqualToDictionary:_additionalChannelArgs])) + [callOptions.additionalChannelArgs isEqualToDictionary:_additionalChannelArgs])) return NO; if (!(callOptions.PEMRootCertificates == _PEMRootCertificates || [callOptions.PEMRootCertificates isEqualToString:_PEMRootCertificates])) @@ -256,8 +256,7 @@ static NSUInteger kDefaultChannelID = 0; [callOptions.hostNameOverride isEqualToString:_hostNameOverride])) return NO; if (!(callOptions.transportType == _transportType)) return NO; - if (!(callOptions.logContext == _logContext || - [callOptions.logContext isEqual:_logContext])) + if (!(callOptions.logContext == _logContext || [callOptions.logContext isEqual:_logContext])) return NO; if (!(callOptions.channelPoolDomain == _channelPoolDomain || [callOptions.channelPoolDomain isEqualToString:_channelPoolDomain])) @@ -335,7 +334,7 @@ static NSUInteger kDefaultChannelID = 0; connectInitialBackoff:kDefaultConnectInitialBackoff connectMaxBackoff:kDefaultConnectMaxBackoff additionalChannelArgs:kDefaultAdditionalChannelArgs - PEMRootCertificates:kDefaultPEMRootCertificates + PEMRootCertificates:kDefaultPEMRootCertificates PEMPrivateKey:kDefaultPEMPrivateKey PEMCertChain:kDefaultPEMCertChain transportType:kDefaultTransportType @@ -362,7 +361,7 @@ static NSUInteger kDefaultChannelID = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:[_additionalChannelArgs copy] - PEMRootCertificates:_PEMRootCertificates + PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey PEMCertChain:_PEMCertChain transportType:_transportType @@ -390,7 +389,7 @@ static NSUInteger kDefaultChannelID = 0; connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff additionalChannelArgs:[_additionalChannelArgs copy] - PEMRootCertificates:_PEMRootCertificates + PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey PEMCertChain:_PEMCertChain transportType:_transportType @@ -482,7 +481,8 @@ static NSUInteger kDefaultChannelID = 0; } - (void)setAdditionalChannelArgs:(NSDictionary *)additionalChannelArgs { - _additionalChannelArgs = [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; + _additionalChannelArgs = + [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; } - (void)setPEMRootCertificates:(NSString *)PEMRootCertificates { diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 2420988f42..63bc267a76 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -75,8 +75,12 @@ NSTimeInterval kChannelDestroyDelay = 30; _refCount = 1; _disconnected = NO; if (@available(iOS 8.0, *)) { - _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); - _timerQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_DEFAULT, -1)); + _dispatchQueue = dispatch_queue_create( + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + _timerQueue = + dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class( + DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_DEFAULT, -1)); } else { _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); _timerQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); @@ -101,7 +105,8 @@ NSTimeInterval kChannelDestroyDelay = 30; self->_refCount--; if (self->_refCount == 0) { self->_lastDispatch = [NSDate date]; - dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)kChannelDestroyDelay * 1e9); + dispatch_time_t delay = + dispatch_time(DISPATCH_TIME_NOW, (int64_t)kChannelDestroyDelay * 1e9); dispatch_after(delay, self->_timerQueue, ^{ [self timerFire]; }); @@ -123,7 +128,8 @@ NSTimeInterval kChannelDestroyDelay = 30; - (void)timerFire { dispatch_async(_dispatchQueue, ^{ - if (self->_disconnected || self->_lastDispatch == nil || -[self->_lastDispatch timeIntervalSinceNow] < -kChannelDestroyDelay) { + if (self->_disconnected || self->_lastDispatch == nil || + -[self->_lastDispatch timeIntervalSinceNow] < -kChannelDestroyDelay) { return; } self->_lastDispatch = nil; @@ -158,11 +164,12 @@ NSTimeInterval kChannelDestroyDelay = 30; } grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); gpr_timespec deadline_ms = - timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); - call = grpc_channel_create_call( - self->_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, + timeout == 0 + ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + call = grpc_channel_create_call(self->_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, + queue.unmanagedQueue, path_slice, serverAuthority ? &host_slice : NULL, deadline_ms, NULL); if (serverAuthority) { grpc_slice_unref(host_slice); @@ -214,11 +221,14 @@ NSTimeInterval kChannelDestroyDelay = 30; if ((self = [super init])) { _unmanagedChannel = unmanagedChannel; _configuration = configuration; - _channelRef = [[GRPCChannelRef alloc] initWithDestroyDelay:kChannelDestroyDelay destroyChannelCallback:^{ - [self destroyChannel]; - }]; + _channelRef = [[GRPCChannelRef alloc] initWithDestroyDelay:kChannelDestroyDelay + destroyChannelCallback:^{ + [self destroyChannel]; + }]; if (@available(iOS 8.0, *)) { - _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + _dispatchQueue = dispatch_queue_create( + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); } else { _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 5d53cb2e99..6659d193c6 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -52,10 +52,11 @@ extern const char *kCFStreamVarName; #ifdef GRPC_COMPILE_WITH_CRONET if (![GRPCCall isUsingCronet]) { #endif - factory = [GRPCSecureChannelFactory factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates - privateKey:_callOptions.PEMPrivateKey - certChain:_callOptions.PEMCertChain - error:&error]; + factory = [GRPCSecureChannelFactory + factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates + privateKey:_callOptions.PEMPrivateKey + certChain:_callOptions.PEMCertChain + error:&error]; if (factory == nil) { NSLog(@"Error creating secure channel factory: %@", error); } @@ -136,7 +137,8 @@ extern const char *kCFStreamVarName; } - (nonnull id)copyWithZone:(nullable NSZone *)zone { - GRPCChannelConfiguration *newConfig = [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; + GRPCChannelConfiguration *newConfig = + [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; return newConfig; } @@ -145,7 +147,8 @@ extern const char *kCFStreamVarName; NSAssert([object isKindOfClass:[GRPCChannelConfiguration class]], @"Illegal :isEqual"); GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; if (!(obj.host == _host || [obj.host isEqualToString:_host])) return NO; - if (!(obj.callOptions == _callOptions || [obj.callOptions isChannelOptionsEqualTo:_callOptions])) return NO; + if (!(obj.callOptions == _callOptions || [obj.callOptions isChannelOptionsEqualTo:_callOptions])) + return NO; return YES; } @@ -201,11 +204,13 @@ extern const char *kCFStreamVarName; - (void)removeChannel:(GRPCChannel *)channel { @synchronized(self) { - [_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannel * _Nonnull obj, BOOL * _Nonnull stop) { - if (obj == channel) { - [self->_channelPool removeObjectForKey:key]; - } - }]; + [_channelPool + enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration *_Nonnull key, + GRPCChannel *_Nonnull obj, BOOL *_Nonnull stop) { + if (obj == channel) { + [self->_channelPool removeObjectForKey:key]; + } + }]; } } @@ -217,9 +222,11 @@ extern const char *kCFStreamVarName; - (void)removeAndCloseAllChannels { @synchronized(self) { - [_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannel * _Nonnull obj, BOOL * _Nonnull stop) { - [obj disconnect]; - }]; + [_channelPool + enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration *_Nonnull key, + GRPCChannel *_Nonnull obj, BOOL *_Nonnull stop) { + [obj disconnect]; + }]; _channelPool = [NSMutableDictionary dictionary]; } } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index db1e8c6deb..f2ba513495 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -24,7 +24,7 @@ @class GPBMessage; /** An object can implement this protocol to receive responses from server from a call. */ -@protocol GRPCProtoResponseHandler +@protocol GRPCProtoResponseHandler @optional @@ -59,7 +59,7 @@ - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** * Users should not use this initializer directly. Call objects will be created, initialized, and @@ -81,7 +81,7 @@ - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** * Users should not use this initializer directly. Call objects will be created, initialized, and diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index d3005e30a5..238faa3343 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -88,7 +88,9 @@ _callOptions = [callOptions copy]; _responseClass = responseClass; if (@available(iOS 8.0, *)) { - _dispatchQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + _dispatchQueue = dispatch_queue_create( + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); } else { _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); } @@ -120,9 +122,9 @@ error:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeCancelled userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; }); } _handler = nil; diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index 2985c5cb2d..3a16ab2402 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -30,14 +30,15 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoService : NSObject -- (instancetype)init NS_UNAVAILABLE; + - + (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; - - - (instancetype)initWithHost : (NSString *)host packageName - : (NSString *)packageName serviceName : (NSString *)serviceName callOptions - : (GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithHost:(NSString *)host + packageName:(NSString *)packageName + serviceName:(NSString *)serviceName + callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; - (instancetype)initWithHost:(NSString *)host packageName:(NSString *)packageName diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index db64ac6339..f4a9fb4a2c 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -57,11 +57,9 @@ NSString *kDummyHost = @"dummy.host"; GRPCChannelConfiguration *config1 = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - GRPCChannel *channel1 = - [pool channelWithConfiguration:config1]; + GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; [pool removeChannel:channel1]; - GRPCChannel *channel2 = - [pool channelWithConfiguration:config1]; + GRPCChannel *channel2 = [pool channelWithConfiguration:config1]; XCTAssertNotEqual(channel1, channel2); } @@ -74,18 +72,14 @@ extern NSTimeInterval kChannelDestroyDelay; options1.transportType = GRPCTransportTypeInsecure; GRPCChannelConfiguration *config1 = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; - GRPCChannelPool *pool = - [[GRPCChannelPool alloc] init]; - GRPCChannel *channel1 = - [pool channelWithConfiguration:config1]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; [channel1 unmanagedCallUnref]; sleep(1); - GRPCChannel *channel2 = - [pool channelWithConfiguration:config1]; + GRPCChannel *channel2 = [pool channelWithConfiguration:config1]; XCTAssertEqual(channel1, channel2); sleep((int)kChannelDestroyDelay + 2); - GRPCChannel *channel3 = - [pool channelWithConfiguration:config1]; + GRPCChannel *channel3 = [pool channelWithConfiguration:config1]; XCTAssertEqual(channel1, channel3); kChannelDestroyDelay = kOriginalInterval; } @@ -96,12 +90,11 @@ extern NSTimeInterval kChannelDestroyDelay; options1.transportType = GRPCTransportTypeInsecure; GRPCCallOptions *options2 = [options1 copy]; GRPCChannelConfiguration *config1 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; GRPCChannelConfiguration *config2 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; [pool removeAndCloseAllChannels]; GRPCChannel *channel2 = [pool channelWithConfiguration:config2]; @@ -119,17 +112,13 @@ extern NSTimeInterval kChannelDestroyDelay; [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - GRPCChannel *channel1 = - [pool channelWithConfiguration:config1]; - GRPCChannel *channel2 = - [pool channelWithConfiguration:config2]; + GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; + GRPCChannel *channel2 = [pool channelWithConfiguration:config2]; XCTAssertNotEqual(channel1, channel2); [pool removeAndCloseAllChannels]; - GRPCChannel *channel3 = - [pool channelWithConfiguration:config1]; - GRPCChannel *channel4 = - [pool channelWithConfiguration:config2]; + GRPCChannel *channel3 = [pool channelWithConfiguration:config1]; + GRPCChannel *channel4 = [pool channelWithConfiguration:config2]; XCTAssertNotEqual(channel1, channel3); XCTAssertNotEqual(channel2, channel4); } diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index f961b6a86f..387fcab7e9 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -446,42 +446,40 @@ static GRPCProtoMethod *kFullDuplexCallMethod; options.initialMetadata = headers; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:request - responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^( + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^( NSDictionary *initialMetadata) { - NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"]; - // Test the regex is correct - NSString *expectedUserAgent = @"Foo grpc-objc/"; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; - expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"]; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "]; - expectedUserAgent = [expectedUserAgent - stringByAppendingString:[NSString - stringWithUTF8String:grpc_g_stands_for()]]; - expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"]; - XCTAssertEqualObjects(userAgent, expectedUserAgent); - - NSError *error = nil; - // Change in format of user-agent field in a direction that does not match - // the regex will likely cause problem for certain gRPC users. For details, - // refer to internal doc https://goo.gl/c2diBc - NSRegularExpression *regex = [NSRegularExpression - regularExpressionWithPattern: - @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" - options:0 - error:&error]; - - NSString *customUserAgent = [regex - stringByReplacingMatchesInString:userAgent - options:0 - range:NSMakeRange(0, [userAgent length]) - withTemplate:@""]; - XCTAssertEqualObjects(customUserAgent, @"Foo"); - [recvInitialMd fulfill]; - } + NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"]; + // Test the regex is correct + NSString *expectedUserAgent = @"Foo grpc-objc/"; + expectedUserAgent = + [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"]; + expectedUserAgent = + [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "]; + expectedUserAgent = [expectedUserAgent + stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"]; + XCTAssertEqualObjects(userAgent, expectedUserAgent); + + NSError *error = nil; + // Change in format of user-agent field in a direction that does not match + // the regex will likely cause problem for certain gRPC users. For details, + // refer to internal doc https://goo.gl/c2diBc + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern: + @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" + options:0 + error:&error]; + + NSString *customUserAgent = + [regex stringByReplacingMatchesInString:userAgent + options:0 + range:NSMakeRange(0, [userAgent length]) + withTemplate:@""]; + XCTAssertEqualObjects(customUserAgent, @"Foo"); + [recvInitialMd fulfill]; + } messageCallback:^(id message) { XCTAssertNotNil(message); XCTAssertEqual([message length], 0, @@ -609,7 +607,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; options.transportType = GRPCTransportTypeInsecure; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions - responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id message) { NSData *data = (NSData *)message; XCTAssertNotNil(data, @"nil value received as response."); @@ -739,19 +737,18 @@ static GRPCProtoMethod *kFullDuplexCallMethod; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions - responseHandler: - [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil - messageCallback:^(id data) { - XCTFail( - @"Failure: response received; Expect: no response received."); - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - XCTAssertNotNil(error, - @"Failure: no error received; Expect: receive " - @"deadline exceeded."); - XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded); - [completion fulfill]; - }] + responseHandler: + [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id data) { + XCTFail(@"Failure: response received; Expect: no response received."); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNotNil(error, + @"Failure: no error received; Expect: receive " + @"deadline exceeded."); + XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded); + [completion fulfill]; + }] callOptions:options]; [call start]; @@ -837,7 +834,9 @@ static GRPCProtoMethod *kFullDuplexCallMethod; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; NSString *const kDummyAddress = [NSString stringWithFormat:@"127.0.0.1:10000"]; GRPCRequestOptions *requestOptions = - [[GRPCRequestOptions alloc] initWithHost:kDummyAddress path:@"/dummy/path" safety:GRPCCallSafetyDefault]; + [[GRPCRequestOptions alloc] initWithHost:kDummyAddress + path:@"/dummy/path" + safety:GRPCCallSafetyDefault]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.connectMinTimeout = timeout; options.connectInitialBackoff = backoff; @@ -846,7 +845,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; NSDate *startTime = [NSDate date]; GRPCCall2 *call = [[GRPCCall2 alloc] initWithRequestOptions:requestOptions - responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id data) { XCTFail(@"Received message. Should not reach here."); } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index ca49b5fc39..1188a75df7 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -483,7 +483,7 @@ BOOL isRemoteInteropTest(NSString *host) { id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.transportType = [[self class] transportType ]; + options.transportType = [[self class] transportType]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; -- cgit v1.2.3 From 6d8340847caf0634853818ff4b8745e83c5279d3 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 09:12:18 -0700 Subject: Name changes in compiler --- src/compiler/objective_c_generator.cc | 4 ++-- src/compiler/objective_c_plugin.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc index eb67e9bb88..0a6b64f595 100644 --- a/src/compiler/objective_c_generator.cc +++ b/src/compiler/objective_c_generator.cc @@ -127,11 +127,11 @@ void PrintV2Signature(Printer* printer, const MethodDescriptor* method, printer->Print(vars, "- ($return_type$)$method_name$With"); if (method->client_streaming()) { - printer->Print("ResponseHandler:(id)handler"); + printer->Print("ResponseHandler:(id)handler"); } else { printer->Print(vars, "Message:($request_class$ *)message " - "responseHandler:(id)handler"); + "responseHandler:(id)handler"); } printer->Print(" callOptions:(GRPCCallOptions *_Nullable)callOptions"); } diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc index d0ef9ed0d6..87977095d0 100644 --- a/src/compiler/objective_c_plugin.cc +++ b/src/compiler/objective_c_plugin.cc @@ -98,7 +98,7 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { "@class GRPCUnaryProtoCall;\n" "@class GRPCStreamingProtoCall;\n" "@class GRPCCallOptions;\n" - "@protocol GRPCResponseHandler;\n" + "@protocol GRPCProtoResponseHandler;\n" "\n"; ::grpc::string class_declarations = -- cgit v1.2.3 From 82d91964493ceb5893b3874109bc4bbc7d87b821 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 09:12:59 -0700 Subject: One more obj.class->[obj class] --- .../tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m index 237804d23d..b0d4e4883a 100644 --- a/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m +++ b/src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m @@ -105,7 +105,7 @@ dispatch_once_t initCronet; // Local stack with SSL _localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost]; - NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"]; NSError *error = nil; -- cgit v1.2.3 From b9667c6c17590c1f63435ad8dab0554775299003 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 09:13:27 -0700 Subject: handle NULL case when parsing certificate --- .../GRPCClient/private/GRPCSecureChannelFactory.m | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 13bca6c40d..90482cad21 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -42,6 +42,9 @@ NS_ASSUME_NONNULL_BEGIN - (NSData *)nullTerminatedDataWithString:(NSString *)string { // dataUsingEncoding: does not return a null-terminated string. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + if (data == nil) { + return nil; + } NSMutableData *nullTerminated = [NSMutableData dataWithData:data]; [nullTerminated appendBytes:"\0" length:1]; return nullTerminated; @@ -51,7 +54,7 @@ NS_ASSUME_NONNULL_BEGIN privateKey:(nullable NSString *)privateKey certChain:(nullable NSString *)certChain error:(NSError **)errorPtr { - static NSData *kDefaultRootsASCII; + static NSData *defaultRootsASCII; static NSError *kDefaultRootsError; static dispatch_once_t loading; dispatch_once(&loading, ^{ @@ -68,14 +71,14 @@ NS_ASSUME_NONNULL_BEGIN kDefaultRootsError = error; return; } - kDefaultRootsASCII = [self nullTerminatedDataWithString:contentInUTF8]; + defaultRootsASCII = [self nullTerminatedDataWithString:contentInUTF8]; }); NSData *rootsASCII; if (rootCerts != nil) { rootsASCII = [self nullTerminatedDataWithString:rootCerts]; } else { - if (kDefaultRootsASCII == nil) { + if (defaultRootsASCII == nil) { if (errorPtr) { *errorPtr = kDefaultRootsError; } @@ -88,11 +91,11 @@ NS_ASSUME_NONNULL_BEGIN kDefaultRootsError); return nil; } - rootsASCII = kDefaultRootsASCII; + rootsASCII = defaultRootsASCII; } - grpc_channel_credentials *creds; - if (privateKey == nil && certChain == nil) { + grpc_channel_credentials *creds = NULL; + if (privateKey.length == 0 && certChain.length == 0) { creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL); } else { grpc_ssl_pem_key_cert_pair key_cert_pair; @@ -100,7 +103,11 @@ NS_ASSUME_NONNULL_BEGIN NSData *certChainASCII = [self nullTerminatedDataWithString:certChain]; key_cert_pair.private_key = privateKeyASCII.bytes; key_cert_pair.cert_chain = certChainASCII.bytes; - creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL, NULL); + if (key_cert_pair.private_key == NULL || key_cert_pair.cert_chain == NULL) { + creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL); + } else { + creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL, NULL); + } } if ((self = [super init])) { -- cgit v1.2.3 From 56d605230f2d8c2ddb5670e8d0f2ede6c2aca4d1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 09:17:11 -0700 Subject: nil->NULL --- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 90482cad21..3f2769bf44 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -126,7 +126,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)dealloc { - if (_channelCreds != nil) { + if (_channelCreds != NULL) { grpc_channel_credentials_release(_channelCreds); } } -- cgit v1.2.3 From 75f8727a3e35ac3db8a3957d9318f2dfdd798e7f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 09:26:38 -0700 Subject: NSString == nil -> NSString.length == 0 --- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 1c03bc9efd..a7c50a1751 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -247,7 +247,7 @@ - (instancetype)initWithHost:(NSString *)host path:(NSString *)path callOptions:(GRPCCallOptions *)callOptions { - if (!path || !host) { + if (host.length == 0 || path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"path and host cannot be nil."]; } -- cgit v1.2.3 From 2a9efc3d1f0ddb42d0797dee5f82ca7abedc0936 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 09:50:33 -0700 Subject: polish cancel message of proto calls --- src/objective-c/ProtoRPC/ProtoRPC.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index f2ba513495..663c1610bc 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -71,7 +71,11 @@ callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; -/** Cancel the call at best effort. */ +/** + * Cancel the request of this call at best effort. It attempts to notify the server that the RPC + * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code + * CANCELED if no other error code has already been issued. + */ - (void)cancel; @end @@ -92,7 +96,11 @@ callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; -/** Cancel the call at best effort. */ +/** + * Cancel the request of this call at best effort. It attempts to notify the server that the RPC + * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code + * CANCELED if no other error code has already been issued. + */ - (void)cancel; /** -- cgit v1.2.3 From 9925c13b2710a313d489fd040f0d7f312af0f1fc Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 09:51:42 -0700 Subject: writeWithMessage->writeMessage --- src/objective-c/ProtoRPC/ProtoRPC.h | 2 +- src/objective-c/ProtoRPC/ProtoRPC.m | 4 ++-- src/objective-c/tests/InteropTests.m | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 663c1610bc..4121d4f6af 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -107,7 +107,7 @@ * Send a message to the server. The message should be a Protobuf message which will be serialized * internally. */ -- (void)writeWithMessage:(GPBMessage *)message; +- (void)writeMessage:(GPBMessage *)message; /** * Finish the RPC request and half-close the call. The server may still send messages and/or diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 238faa3343..b04b6aca67 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -41,7 +41,7 @@ responseHandler:handler callOptions:callOptions responseClass:responseClass]; - [_call writeWithMessage:message]; + [_call writeMessage:message]; [_call finish]; } return self; @@ -132,7 +132,7 @@ }); } -- (void)writeWithMessage:(GPBMessage *)message { +- (void)writeMessage:(GPBMessage *)message { if (![message isKindOfClass:[GPBMessage class]]) { [NSException raise:NSInvalidArgumentException format:@"Data must be a valid protobuf type."]; } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 1188a75df7..d38e1e0d97 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -501,7 +501,7 @@ BOOL isRemoteInteropTest(NSString *host) { id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; - [call writeWithMessage:request]; + [call writeMessage:request]; } else { [call finish]; } @@ -517,7 +517,7 @@ BOOL isRemoteInteropTest(NSString *host) { [expectation fulfill]; }] callOptions:options]; - [call writeWithMessage:request]; + [call writeMessage:request]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -651,7 +651,7 @@ BOOL isRemoteInteropTest(NSString *host) { }] callOptions:options]; - [call writeWithMessage:request]; + [call writeMessage:request]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- cgit v1.2.3 From 2d903f4732ee21c5c319c88aa738671b56b2e729 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 10:15:02 -0700 Subject: More specific typing in response handlers --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/ProtoRPC/ProtoRPC.h | 2 +- src/objective-c/ProtoRPC/ProtoRPC.m | 2 +- src/objective-c/tests/GRPCClientTests.m | 2 +- src/objective-c/tests/InteropTests.m | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index bd43a0a384..d8d3e3cf62 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -160,7 +160,7 @@ extern id const kGRPCTrailersKey; * Issued when a message is received from the server. The message is the raw data received from the * server, with decompression and without proto deserialization. */ -- (void)receivedRawMessage:(id)message; +- (void)receivedRawMessage:(NSData *)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 4121d4f6af..34a519bee5 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -34,7 +34,7 @@ /** * Issued when a message is received from the server. The message is the deserialized proto object. */ -- (void)receivedProtoMessage:(id)message; +- (void)receivedProtoMessage:(GPBMessage *)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index b04b6aca67..44e9bfde0a 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -168,7 +168,7 @@ if (_handler) { id handler = _handler; NSError *error = nil; - id parsed = [_responseClass parseFromData:message error:&error]; + GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; if (parsed) { if ([handler respondsToSelector:@selector(receivedProtoMessage:)]) { dispatch_async(handler.dispatchQueue, ^{ diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 387fcab7e9..985e105b81 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -120,7 +120,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } } -- (void)receivedProtoMessage:(id)message { +- (void)receivedProtoMessage:(GPBMessage *)message { if (_messageCallback) { _messageCallback(message); } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index d38e1e0d97..a9f33aab6f 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -108,7 +108,7 @@ BOOL isRemoteInteropTest(NSString *host) { } } -- (void)receivedProtoMessage:(id)message { +- (void)receivedProtoMessage:(GPBMessage *)message { if (_messageCallback) { _messageCallback(message); } -- cgit v1.2.3 From a6e35201b5a00949379fd04fb784f6b90d06a88a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 11:07:00 -0700 Subject: polish comments --- src/objective-c/GRPCClient/GRPCCallOptions.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 8864bcb8a2..6e16cd56a9 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -26,8 +26,10 @@ typedef NS_ENUM(NSUInteger, GRPCCallSafety) { GRPCCallSafetyDefault = 0, /** Signal that the call is idempotent. gRPC is free to use PUT verb. */ GRPCCallSafetyIdempotentRequest = 1, - /** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET - verb. */ + /** + * Signal that the call is cacheable and will not affect server state. gRPC is free to use GET + * verb. + */ GRPCCallSafetyCacheableRequest = 2, }; @@ -39,14 +41,14 @@ typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) { GRPCStreamCompressGzip, }; -// The transport to be used by a gRPC call +/** The transport to be used by a gRPC call */ typedef NS_ENUM(NSInteger, GRPCTransportType) { GRPCTransportTypeDefault = 0, - // gRPC internal HTTP/2 stack with BoringSSL + /** gRPC internal HTTP/2 stack with BoringSSL */ GRPCTransportTypeChttp2BoringSSL = 0, - // Cronet stack + /** Cronet stack */ GRPCTransportTypeCronet, - // Insecure channel. FOR TEST ONLY! + /** Insecure channel. FOR TEST ONLY! */ GRPCTransportTypeInsecure, }; -- cgit v1.2.3 From 590ab392520c0216690bc2626e2c9b55e95fc0fa Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 11:24:04 -0700 Subject: GRPCCompressAlgorithm->GRPCCompressionAlgorithm --- src/objective-c/GRPCClient/GRPCCallOptions.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 6e16cd56a9..b8bbb8a22d 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -33,14 +33,19 @@ typedef NS_ENUM(NSUInteger, GRPCCallSafety) { GRPCCallSafetyCacheableRequest = 2, }; + + // Compression algorithm to be used by a gRPC call -typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) { +typedef NS_ENUM(NSInteger, GRPCCompressionAlgorithm) { GRPCCompressNone = 0, GRPCCompressDeflate, GRPCCompressGzip, GRPCStreamCompressGzip, }; +// GRPCCompressAlgorithm is deprecated; use GRPCCompressionAlgorithm +typedef GRPCCompressionAlgorithm GRPCCompressAlgorithm; + /** The transport to be used by a gRPC call */ typedef NS_ENUM(NSInteger, GRPCTransportType) { GRPCTransportTypeDefault = 0, -- cgit v1.2.3 From cc9157a248e20a2f24972241ae1f2d41ea171a8b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 11:45:59 -0700 Subject: Polish comments --- src/objective-c/GRPCClient/GRPCCallOptions.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index b8bbb8a22d..9a8362cbcc 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -67,7 +67,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * The authority for the RPC. If nil, the default authority will be used. * - * Note: This property must be nil when Cronet transport is enabled. + * Note: This property does not have effect on Cronet transport and will be ignored. * Note: This property cannot be used to validate a self-signed server certificate. It control the * :authority header field of the call and performs an extra check that server's certificate * matches the :authority header. @@ -85,8 +85,8 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * The OAuth2 access token string. The string is prefixed with "Bearer " then used as value of the - * request's "authorization" header field. This parameter should not be used simultaneously with - * \a authTokenProvider. + * request's "authorization" header field. This parameter takes precedence over \a + * oauth2AccessToken. */ @property(copy, readonly) NSString *oauth2AccessToken; @@ -213,7 +213,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * The authority for the RPC. If nil, the default authority will be used. * - * Note: This property must be nil when Cronet transport is enabled. + * Note: This property does not have effect on Cronet transport and will be ignored. * Note: This property cannot be used to validate a self-signed server certificate. It control the * :authority header field of the call and performs an extra check that server's certificate * matches the :authority header. @@ -239,7 +239,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when - * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken. + * initiating the call. This parameter takes precedence over \a oauth2AccessToken. */ @property(readwrite) id authTokenProvider; -- cgit v1.2.3 From 9f9141082bcd4167488780f93eeec8d40c17e007 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 11:57:18 -0700 Subject: compressAlgorithm->compressionAlgorithm --- src/objective-c/GRPCClient/GRPCCallOptions.h | 4 +-- src/objective-c/GRPCClient/GRPCCallOptions.m | 32 +++++++++++----------- .../GRPCClient/private/GRPCChannelPool.m | 4 +-- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 9a8362cbcc..484f15fde6 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -119,7 +119,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * The compression algorithm to be used by the gRPC call. For more details refer to * https://github.com/grpc/grpc/blob/master/doc/compression.md */ -@property(readonly) GRPCCompressAlgorithm compressAlgorithm; +@property(readonly) GRPCCompressionAlgorithm compressionAlgorithm; /** * Enable/Disable gRPC call's retry feature. The default is enabled. For details of this feature @@ -266,7 +266,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * The compression algorithm to be used by the gRPC call. For more details refer to * https://github.com/grpc/grpc/blob/master/doc/compression.md */ -@property(readwrite) GRPCCompressAlgorithm compressAlgorithm; +@property(readwrite) GRPCCompressionAlgorithm compressionAlgorithm; /** * Enable/Disable gRPC call's retry feature. The default is enabled. For details of this feature diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 37ed3ebd1d..3dc21b7287 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -24,7 +24,7 @@ static const NSTimeInterval kDefaultTimeout = 0; static NSDictionary *const kDefaultInitialMetadata = nil; static NSString *const kDefaultUserAgentPrefix = nil; static const NSUInteger kDefaultResponseSizeLimit = 0; -static const GRPCCompressAlgorithm kDefaultCompressAlgorithm = GRPCCompressNone; +static const GRPCCompressionAlgorithm kDefaultCompressionAlgorithm = GRPCCompressNone; static const BOOL kDefaultEnableRetry = YES; static const NSTimeInterval kDefaultKeepaliveInterval = 0; static const NSTimeInterval kDefaultKeepaliveTimeout = 0; @@ -52,7 +52,7 @@ static NSUInteger kDefaultChannelID = 0; NSDictionary *_initialMetadata; NSString *_userAgentPrefix; NSUInteger _responseSizeLimit; - GRPCCompressAlgorithm _compressAlgorithm; + GRPCCompressionAlgorithm _compressionAlgorithm; BOOL _enableRetry; NSTimeInterval _keepaliveInterval; NSTimeInterval _keepaliveTimeout; @@ -77,7 +77,7 @@ static NSUInteger kDefaultChannelID = 0; @synthesize initialMetadata = _initialMetadata; @synthesize userAgentPrefix = _userAgentPrefix; @synthesize responseSizeLimit = _responseSizeLimit; -@synthesize compressAlgorithm = _compressAlgorithm; +@synthesize compressionAlgorithm = _compressionAlgorithm; @synthesize enableRetry = _enableRetry; @synthesize keepaliveInterval = _keepaliveInterval; @synthesize keepaliveTimeout = _keepaliveTimeout; @@ -102,7 +102,7 @@ static NSUInteger kDefaultChannelID = 0; initialMetadata:kDefaultInitialMetadata userAgentPrefix:kDefaultUserAgentPrefix responseSizeLimit:kDefaultResponseSizeLimit - compressAlgorithm:kDefaultCompressAlgorithm + compressionAlgorithm:kDefaultCompressionAlgorithm enableRetry:kDefaultEnableRetry keepaliveInterval:kDefaultKeepaliveInterval keepaliveTimeout:kDefaultKeepaliveTimeout @@ -127,7 +127,7 @@ static NSUInteger kDefaultChannelID = 0; initialMetadata:(NSDictionary *)initialMetadata userAgentPrefix:(NSString *)userAgentPrefix responseSizeLimit:(NSUInteger)responseSizeLimit - compressAlgorithm:(GRPCCompressAlgorithm)compressAlgorithm + compressionAlgorithm:(GRPCCompressionAlgorithm)compressionAlgorithm enableRetry:(BOOL)enableRetry keepaliveInterval:(NSTimeInterval)keepaliveInterval keepaliveTimeout:(NSTimeInterval)keepaliveTimeout @@ -151,7 +151,7 @@ static NSUInteger kDefaultChannelID = 0; _initialMetadata = [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES]; _userAgentPrefix = [userAgentPrefix copy]; _responseSizeLimit = responseSizeLimit; - _compressAlgorithm = compressAlgorithm; + _compressionAlgorithm = compressionAlgorithm; _enableRetry = enableRetry; _keepaliveInterval = keepaliveInterval; _keepaliveTimeout = keepaliveTimeout; @@ -181,7 +181,7 @@ static NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressAlgorithm:_compressAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout @@ -209,7 +209,7 @@ static NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressAlgorithm:_compressAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout @@ -233,7 +233,7 @@ static NSUInteger kDefaultChannelID = 0; [callOptions.userAgentPrefix isEqualToString:_userAgentPrefix])) return NO; if (!(callOptions.responseSizeLimit == _responseSizeLimit)) return NO; - if (!(callOptions.compressAlgorithm == _compressAlgorithm)) return NO; + if (!(callOptions.compressionAlgorithm == _compressionAlgorithm)) return NO; if (!(callOptions.enableRetry == _enableRetry)) return NO; if (!(callOptions.keepaliveInterval == _keepaliveInterval)) return NO; if (!(callOptions.keepaliveTimeout == _keepaliveTimeout)) return NO; @@ -270,7 +270,7 @@ static NSUInteger kDefaultChannelID = 0; NSUInteger result = 0; result ^= _userAgentPrefix.hash; result ^= _responseSizeLimit; - result ^= _compressAlgorithm; + result ^= _compressionAlgorithm; result ^= _enableRetry; result ^= (unsigned int)(_keepaliveInterval * 1000); result ^= (unsigned int)(_keepaliveTimeout * 1000); @@ -301,7 +301,7 @@ static NSUInteger kDefaultChannelID = 0; @dynamic initialMetadata; @dynamic userAgentPrefix; @dynamic responseSizeLimit; -@dynamic compressAlgorithm; +@dynamic compressionAlgorithm; @dynamic enableRetry; @dynamic keepaliveInterval; @dynamic keepaliveTimeout; @@ -326,7 +326,7 @@ static NSUInteger kDefaultChannelID = 0; initialMetadata:kDefaultInitialMetadata userAgentPrefix:kDefaultUserAgentPrefix responseSizeLimit:kDefaultResponseSizeLimit - compressAlgorithm:kDefaultCompressAlgorithm + compressionAlgorithm:kDefaultCompressionAlgorithm enableRetry:kDefaultEnableRetry keepaliveInterval:kDefaultKeepaliveInterval keepaliveTimeout:kDefaultKeepaliveTimeout @@ -353,7 +353,7 @@ static NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressAlgorithm:_compressAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout @@ -381,7 +381,7 @@ static NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressAlgorithm:_compressAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout @@ -432,8 +432,8 @@ static NSUInteger kDefaultChannelID = 0; _responseSizeLimit = responseSizeLimit; } -- (void)setCompressAlgorithm:(GRPCCompressAlgorithm)compressAlgorithm { - _compressAlgorithm = compressAlgorithm; +- (void)setCompressionAlgorithm:(GRPCCompressionAlgorithm)compressionAlgorithm { + _compressionAlgorithm = compressionAlgorithm; } - (void)setEnableRetry:(BOOL)enableRetry { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 6659d193c6..4908b82fea 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -94,9 +94,9 @@ extern const char *kCFStreamVarName; [NSNumber numberWithUnsignedInteger:_callOptions.responseSizeLimit]; } - if (_callOptions.compressAlgorithm != GRPC_COMPRESS_NONE) { + if (_callOptions.compressionAlgorithm != GRPC_COMPRESS_NONE) { args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = - [NSNumber numberWithInt:_callOptions.compressAlgorithm]; + [NSNumber numberWithInt:_callOptions.compressionAlgorithm]; } if (_callOptions.keepaliveInterval != 0) { diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 5fe022a1ba..41d3bec4ef 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -102,7 +102,7 @@ static NSMutableDictionary *gHostCache; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.userAgentPrefix = _userAgentPrefix; options.responseSizeLimit = _responseSizeLimitOverride; - options.compressAlgorithm = (GRPCCompressAlgorithm)_compressAlgorithm; + options.compressionAlgorithm = (GRPCCompressionAlgorithm)_compressAlgorithm; options.enableRetry = _retryEnabled; options.keepaliveInterval = (NSTimeInterval)_keepaliveInterval / 1000; options.keepaliveTimeout = (NSTimeInterval)_keepaliveTimeout / 1000; -- cgit v1.2.3 From 5eb9911a0eb13590fe558875df3512d6def20d3c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 13:55:31 -0700 Subject: Change extern type --- src/objective-c/GRPCClient/GRPCCall.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index d8d3e3cf62..7ce5a2faf2 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -145,8 +145,8 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) { * Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by * the server. */ -extern id const kGRPCHeadersKey; -extern id const kGRPCTrailersKey; +extern NSString * const kGRPCHeadersKey; +extern NSString * const kGRPCTrailersKey; /** An object can implement this protocol to receive responses from server from a call. */ @protocol GRPCResponseHandler -- cgit v1.2.3 From 0242b022ccc804e498b2e631fd0e6c8478ac97c4 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 14:28:25 -0700 Subject: Typo fix --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 7ce5a2faf2..b8fccc37dc 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -221,7 +221,7 @@ extern NSString * const kGRPCTrailersKey; /** * Designated initializer for a call. * \param requestOptions Protobuf generated parameters for the call. - * \param responseHandler The object to which responses should be issed. + * \param responseHandler The object to which responses should be issued. * \param callOptions Options for the call. */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions -- cgit v1.2.3 From e542e006eb4ffcd0c19488428a3cfe5605bf41e5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 14:29:08 -0700 Subject: Format fix --- src/objective-c/GRPCClient/GRPCCall.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index b8fccc37dc..9fdcd93a30 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -254,7 +254,8 @@ extern NSString * const kGRPCTrailersKey; /** * Finish the RPC request and half-close the call. The server may still send messages and/or * trailers to the client. - */ -(void)finish; + */ +- (void)finish; /** * Get a copy of the original call options. -- cgit v1.2.3 From 422d3296b2d4fb3f8aa0991c2ffa895251ad8e91 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 15:42:39 -0700 Subject: Annotate Nullability --- src/objective-c/GRPCClient/GRPCCall.h | 12 ++++++++---- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/ProtoRPC/ProtoRPC.h | 14 +++++++++----- src/objective-c/ProtoRPC/ProtoRPC.m | 14 +++++++------- src/objective-c/tests/GRPCClientTests.m | 6 +++--- src/objective-c/tests/InteropTests.m | 6 +++--- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 9fdcd93a30..c862609b21 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -39,6 +39,8 @@ #include "GRPCCallOptions.h" +NS_ASSUME_NONNULL_BEGIN + #pragma mark gRPC errors /** Domain of NSError objects produced by gRPC. */ @@ -154,13 +156,13 @@ extern NSString * const kGRPCTrailersKey; @optional /** Issued when initial metadata is received from the server. */ -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; +- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata; /** * Issued when a message is received from the server. The message is the raw data received from the * server, with decompression and without proto deserialization. */ -- (void)receivedRawMessage:(NSData *)message; +- (void)receivedRawMessage:(NSData * _Nullable)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -168,7 +170,7 @@ extern NSString * const kGRPCTrailersKey; * is non-nil and contains the corresponding error information, including gRPC error codes and * error descriptions. */ -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error; +- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error; @required @@ -226,7 +228,7 @@ extern NSString * const kGRPCTrailersKey; */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler - callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; + callOptions:(GRPCCallOptions * _Nullable)callOptions NS_DESIGNATED_INITIALIZER; /** * Convenience initializer for a call that uses default call options (see GRPCCallOptions.m for * the default options). @@ -267,6 +269,8 @@ extern NSString * const kGRPCTrailersKey; @end +NS_ASSUME_NONNULL_END + /** * This interface is deprecated. Please use \a GRPCcall2. * diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index bd4b4e10f0..1782078961 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -97,7 +97,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler - callOptions:(GRPCCallOptions *)callOptions { + callOptions:(GRPCCallOptions * _Nullable)callOptions { if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 34a519bee5..3a7fd58fb1 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -21,6 +21,8 @@ #import "ProtoMethod.h" +NS_ASSUME_NONNULL_BEGIN + @class GPBMessage; /** An object can implement this protocol to receive responses from server from a call. */ @@ -29,12 +31,12 @@ @optional /** Issued when initial metadata is received from the server. */ -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata; +- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata; /** * Issued when a message is received from the server. The message is the deserialized proto object. */ -- (void)receivedProtoMessage:(GPBMessage *)message; +- (void)receivedProtoMessage:(GPBMessage * _Nullable)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -42,7 +44,7 @@ * is non-nil and contains the corresponding error information, including gRPC error codes and * error descriptions. */ -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error; +- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error; @required @@ -68,7 +70,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message responseHandler:(id)handler - callOptions:(GRPCCallOptions *)callOptions + callOptions:(GRPCCallOptions * _Nullable)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** @@ -93,7 +95,7 @@ */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)handler - callOptions:(GRPCCallOptions *)callOptions + callOptions:(GRPCCallOptions * _Nullable)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** @@ -117,6 +119,8 @@ @end +NS_ASSUME_NONNULL_END + __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC : GRPCCall diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 44e9bfde0a..f6e3298f62 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -34,7 +34,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message responseHandler:(id)handler - callOptions:(GRPCCallOptions *)callOptions + callOptions:(GRPCCallOptions * _Nullable)callOptions responseClass:(Class)responseClass { if ((self = [super init])) { _call = [[GRPCStreamingProtoCall alloc] initWithRequestOptions:requestOptions @@ -70,7 +70,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)handler - callOptions:(GRPCCallOptions *)callOptions + callOptions:(GRPCCallOptions * _Nullable)callOptions responseClass:(Class)responseClass { if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; @@ -153,8 +153,8 @@ }); } -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { - if (_handler) { +- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata { + if (_handler && initialMetadata != nil) { id handler = _handler; if ([handler respondsToSelector:@selector(initialMetadata:)]) { dispatch_async(handler.dispatchQueue, ^{ @@ -164,8 +164,8 @@ } } -- (void)receivedRawMessage:(NSData *)message { - if (_handler) { +- (void)receivedRawMessage:(NSData * _Nullable)message { + if (_handler && message != nil) { id handler = _handler; NSError *error = nil; GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; @@ -188,7 +188,7 @@ } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { +- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error { if (_handler) { id handler = _handler; if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 985e105b81..0a9ec97c48 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -114,19 +114,19 @@ static GRPCProtoMethod *kFullDuplexCallMethod; return self; } -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata { if (_initialMetadataCallback) { _initialMetadataCallback(initialMetadata); } } -- (void)receivedProtoMessage:(GPBMessage *)message { +- (void)receivedProtoMessage:(GPBMessage * _Nullable)message { if (_messageCallback) { _messageCallback(message); } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { +- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error { if (_closeCallback) { _closeCallback(trailingMetadata, error); } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index a9f33aab6f..fb49bb99e0 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -102,19 +102,19 @@ BOOL isRemoteInteropTest(NSString *host) { return self; } -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata { if (_initialMetadataCallback) { _initialMetadataCallback(initialMetadata); } } -- (void)receivedProtoMessage:(GPBMessage *)message { +- (void)receivedProtoMessage:(GPBMessage * _Nullable)message { if (_messageCallback) { _messageCallback(message); } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { +- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error { if (_closeCallback) { _closeCallback(trailingMetadata, error); } -- cgit v1.2.3 From 24d952b2b916030aa02f33afb7746b2582ca88e4 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 15:43:46 -0700 Subject: Add comments to ivars of GRPCCall2 --- src/objective-c/GRPCClient/GRPCCall.m | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 1782078961..74b284d924 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -85,13 +85,24 @@ const char *kCFStreamVarName = "grpc_cfstream"; @end @implementation GRPCCall2 { + /** Options for the call. */ GRPCCallOptions *_callOptions; + /** The handler of responses. */ id _handler; + // Thread safety of ivars below are protected by _dispatcheQueue. + + /** + * Make use of legacy GRPCCall to make calls. Nullified when call is finished. + */ GRPCCall *_call; + /** Flags whether initial metadata has been published to response handler. */ BOOL _initialMetadataPublished; + /** Streaming call writeable to the underlying call. */ GRXBufferedPipe *_pipe; + /** Serial dispatch queue for tasks inside the call. */ dispatch_queue_t _dispatchQueue; + /** Flags whether call has started. */ bool _started; } -- cgit v1.2.3 From c6de16fc801b654ff1cbb697c36fafa5c2ff0528 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 15:44:07 -0700 Subject: Remove redundant variable --- src/objective-c/GRPCClient/GRPCCall.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 74b284d924..daa7e8dd4a 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -579,7 +579,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; break; } - uint32_t callFlag = callSafetyFlags; NSMutableDictionary *headers = _requestHeaders; if (_fetchedOauth2AccessToken != nil) { @@ -592,7 +591,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; // TODO(jcanizales): Add error handlers for async failures GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc] initWithMetadata:headers - flags:callFlag + flags:callSafetyFlags handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA if (!_unaryCall) { [_wrappedCall startBatchWithOperations:@[ op ]]; -- cgit v1.2.3 From cb745ceaf9f9ffd90447498a6e8a57d5ac600389 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 15:46:57 -0700 Subject: Synchronized access to fetchedOauth2AccessToken --- src/objective-c/GRPCClient/GRPCCall.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index daa7e8dd4a..34a0e436ea 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -581,8 +581,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; } NSMutableDictionary *headers = _requestHeaders; - if (_fetchedOauth2AccessToken != nil) { - headers[@"authorization"] = [kBearerPrefix stringByAppendingString:_fetchedOauth2AccessToken]; + __block NSString *fetchedOauth2AccessToken; + @synchronized(self) { + fetchedOauth2AccessToken = _fetchedOauth2AccessToken; + } + if (fetchedOauth2AccessToken != nil) { + headers[@"authorization"] = [kBearerPrefix stringByAppendingString:fetchedOauth2AccessToken]; } else if (_callOptions.oauth2AccessToken != nil) { headers[@"authorization"] = [kBearerPrefix stringByAppendingString:_callOptions.oauth2AccessToken]; -- cgit v1.2.3 From 789108d16d72c61b6df4135796116d3cffce0a58 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 17:24:23 -0700 Subject: add const attribute to defaults --- src/objective-c/GRPCClient/GRPCCallOptions.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 3dc21b7287..e148664925 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -40,8 +40,8 @@ static const id kDefaultAuthTokenProvider = nil; static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2BoringSSL; static NSString *const kDefaultHostNameOverride = nil; static const id kDefaultLogContext = nil; -static NSString *kDefaultChannelPoolDomain = nil; -static NSUInteger kDefaultChannelID = 0; +static NSString *const kDefaultChannelPoolDomain = nil; +static const NSUInteger kDefaultChannelID = 0; @implementation GRPCCallOptions { @protected -- cgit v1.2.3 From 8cecb2a86dd5904c68f46d4b685b11c8cb0a8704 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 17:33:50 -0700 Subject: Write comments for functions in ChannelArgsUtil --- src/objective-c/GRPCClient/private/ChannelArgsUtil.h | 9 +++++++++ src/objective-c/GRPCClient/private/ChannelArgsUtil.m | 7 ------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.h b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h index d0be484910..3fb876ecc4 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.h +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h @@ -20,6 +20,15 @@ #include +/** Free resources in the grpc core struct grpc_channel_args */ void GRPCFreeChannelArgs(grpc_channel_args* channel_args); +/** + * Allocates a @c grpc_channel_args and populates it with the options specified in the + * @c dictionary. Keys must be @c NSString, @c NSNumber, or a pointer. If the value responds to + * @c @selector(UTF8String) then it will be mapped to @c GRPC_ARG_STRING. If the value responds to + * @c @selector(intValue), it will be mapped to @c GRPC_ARG_INTEGER. Otherwise, if the value is not + * nil, it is mapped as a pointer. The caller of this function is responsible for calling + * @c GRPCFreeChannelArgs to free the @c grpc_channel_args struct. + */ grpc_channel_args* GRPCBuildChannelArgs(NSDictionary* dictionary); diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m index 8669f79992..b8342a79e7 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -51,13 +51,6 @@ void GRPCFreeChannelArgs(grpc_channel_args *channel_args) { 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 *GRPCBuildChannelArgs(NSDictionary *dictionary) { if (!dictionary) { return NULL; -- cgit v1.2.3 From b3cb4e17f76624e563e51165954ebaa6224d806c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 17:56:42 -0700 Subject: Comment and rename GRPCChannel:ref and :unref --- src/objective-c/GRPCClient/private/GRPCChannel.h | 14 ++++++++++++-- src/objective-c/GRPCClient/private/GRPCChannel.m | 4 ++-- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 2 +- src/objective-c/tests/ChannelTests/ChannelPoolTest.m | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 7a40638dc3..5f5fae0413 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -51,10 +51,20 @@ struct grpc_channel_credentials; completionQueue:(nonnull GRPCCompletionQueue *)queue callOptions:(nonnull GRPCCallOptions *)callOptions; -- (void)unmanagedCallRef; +/** + * Increase the refcount of the channel. If the channel was timed to be destroyed, cancel the timer. + */ +- (void)ref; -- (void)unmanagedCallUnref; +/** + * Decrease the refcount of the channel. If the refcount of the channel decrease to 0, start a timer + * to destroy the channel + */ +- (void)unref; +/** + * Force the channel to be disconnected and destroyed immediately. + */ - (void)disconnect; // TODO (mxyan): deprecate with GRPCCall:closeOpenConnections diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 63bc267a76..3e4db83765 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -180,7 +180,7 @@ NSTimeInterval kChannelDestroyDelay = 30; return call; } -- (void)unmanagedCallRef { +- (void)ref { dispatch_async(_dispatchQueue, ^{ if (self->_unmanagedChannel) { [self->_channelRef refChannel]; @@ -188,7 +188,7 @@ NSTimeInterval kChannelDestroyDelay = 30; }); } -- (void)unmanagedCallUnref { +- (void)unref { dispatch_async(_dispatchQueue, ^{ if (self->_unmanagedChannel) { [self->_channelRef unrefChannel]; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 4908b82fea..8e0f6976cf 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -191,7 +191,7 @@ extern const char *kCFStreamVarName; @synchronized(self) { if ([_channelPool objectForKey:configuration]) { channel = _channelPool[configuration]; - [channel unmanagedCallRef]; + [channel ref]; } else { channel = [GRPCChannel createChannelWithConfiguration:configuration]; if (channel != nil) { diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index a7c50a1751..4d5257aca7 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -311,7 +311,7 @@ - (void)dealloc { grpc_call_unref(_call); - [_channel unmanagedCallUnref]; + [_channel unref]; _channel = nil; } diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index f4a9fb4a2c..5c3f0edba0 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -74,7 +74,7 @@ extern NSTimeInterval kChannelDestroyDelay; [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; - [channel1 unmanagedCallUnref]; + [channel1 unref]; sleep(1); GRPCChannel *channel2 = [pool channelWithConfiguration:config1]; XCTAssertEqual(channel1, channel2); -- cgit v1.2.3 From 17d178363dafe3aa03d348bdbbbd0c3daed9e06e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 17:57:26 -0700 Subject: rename non-const variables --- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 3f2769bf44..aa8b52e6b8 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -55,7 +55,7 @@ NS_ASSUME_NONNULL_BEGIN certChain:(nullable NSString *)certChain error:(NSError **)errorPtr { static NSData *defaultRootsASCII; - static NSError *kDefaultRootsError; + static NSError *defaultRootsError; static dispatch_once_t loading; dispatch_once(&loading, ^{ NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem @@ -68,7 +68,7 @@ NS_ASSUME_NONNULL_BEGIN NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; if (contentInUTF8 == nil) { - kDefaultRootsError = error; + defaultRootsError = error; return; } defaultRootsASCII = [self nullTerminatedDataWithString:contentInUTF8]; @@ -80,15 +80,15 @@ NS_ASSUME_NONNULL_BEGIN } else { if (defaultRootsASCII == nil) { if (errorPtr) { - *errorPtr = kDefaultRootsError; + *errorPtr = defaultRootsError; } NSAssert( - kDefaultRootsASCII, + defaultRootsASCII, @"Could not read gRPCCertificates.bundle/roots.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: %@", - kDefaultRootsError); + defaultRootsError); return nil; } rootsASCII = defaultRootsASCII; -- cgit v1.2.3 From 5e3e744d448c8cd1271cae7e8d40d3bdeaff762f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 19 Oct 2018 18:32:05 -0700 Subject: copy configuration --- src/objective-c/GRPCClient/private/GRPCChannel.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 3e4db83765..6bd852fd0d 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -220,7 +220,7 @@ NSTimeInterval kChannelDestroyDelay = 30; configuration:(GRPCChannelConfiguration *)configuration { if ((self = [super init])) { _unmanagedChannel = unmanagedChannel; - _configuration = configuration; + _configuration = [configuration copy]; _channelRef = [[GRPCChannelRef alloc] initWithDestroyDelay:kChannelDestroyDelay destroyChannelCallback:^{ [self destroyChannel]; -- cgit v1.2.3 From 4186405287a6944e7b1eb59dcae5524ea2db674d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 09:40:22 -0700 Subject: GRPCChannel input parameter sanity check --- src/objective-c/GRPCClient/private/GRPCChannel.m | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 6bd852fd0d..6b5d1fe071 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -150,14 +150,17 @@ NSTimeInterval kChannelDestroyDelay = 30; } - (grpc_call *)unmanagedCallWithPath:(NSString *)path - completionQueue:(nonnull GRPCCompletionQueue *)queue + completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions { + NSAssert(path.length, @"path must not be empty."); + NSAssert(queue, @"completionQueue must not be empty."); + NSAssert(callOptions, @"callOptions must not be empty."); __block grpc_call *call = nil; dispatch_sync(_dispatchQueue, ^{ if (self->_unmanagedChannel) { NSString *serverAuthority = callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; - GPR_ASSERT(timeout >= 0); + NSAssert(timeout >= 0, @"Invalid timeout"); grpc_slice host_slice = grpc_empty_slice(); if (serverAuthority) { host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); @@ -216,8 +219,12 @@ NSTimeInterval kChannelDestroyDelay = 30; }); } -- (nullable instancetype)initWithUnmanagedChannel:(nullable grpc_channel *)unmanagedChannel +- (nullable instancetype)initWithUnmanagedChannel:(grpc_channel * _Nullable)unmanagedChannel configuration:(GRPCChannelConfiguration *)configuration { + NSAssert(configuration, @"Configuration must not be empty."); + if (!unmanagedChannel) { + return nil; + } if ((self = [super init])) { _unmanagedChannel = unmanagedChannel; _configuration = [configuration copy]; -- cgit v1.2.3 From 836640dc4a9e8d62fc0e1218e81076a06a3035a9 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 09:41:34 -0700 Subject: Mark GRPCChannel:new: unavailable --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/GRPCClient/private/GRPCChannel.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index c862609b21..13dcfa0713 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -218,7 +218,7 @@ extern NSString * const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype) new NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; /** * Designated initializer for a call. diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 5f5fae0413..5fb18e0332 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -32,6 +32,8 @@ struct grpc_channel_credentials; - (nullable instancetype)init NS_UNAVAILABLE; ++ (nullable instancetype)new NS_UNAVAILABLE; + /** * Returns a channel connecting to \a host with options as \a callOptions. The channel may be new * or a cached channel that is already connected. -- cgit v1.2.3 From c6fc07d384fe11ca4dc59111b61557053ed3dbac Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 09:44:44 -0700 Subject: Relocate global channel pool variables --- src/objective-c/GRPCClient/private/GRPCChannel.m | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 6b5d1fe071..ac4b88f304 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -32,9 +32,12 @@ #import #import -// When all calls of a channel are destroyed, destroy the channel after this much seconds. +/** When all calls of a channel are destroyed, destroy the channel after this much seconds. */ NSTimeInterval kChannelDestroyDelay = 30; +/** Global instance of channel pool. */ +static GRPCChannelPool *gChannelPool; + /** * Time the channel destroy when the channel's calls are unreffed. If there's new call, reset the * timer. @@ -268,11 +271,9 @@ NSTimeInterval kChannelDestroyDelay = 30; return [[GRPCChannel alloc] initWithUnmanagedChannel:unmanaged_channel configuration:config]; } -static dispatch_once_t initChannelPool; -static GRPCChannelPool *gChannelPool; - + (nullable instancetype)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { + static dispatch_once_t initChannelPool; dispatch_once(&initChannelPool, ^{ gChannelPool = [[GRPCChannelPool alloc] init]; }); -- cgit v1.2.3 From ef830758cc90924e9fdd5be6a451774fad326db0 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 09:50:36 -0700 Subject: Comments to methods of GRPCChannelConfiguration --- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index e9c2ef2bd1..43e07b9845 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -29,12 +29,22 @@ NS_ASSUME_NONNULL_BEGIN @class GRPCChannel; +/** Caching signature of a channel. */ @interface GRPCChannelConfiguration : NSObject +/** The host that this channel is connected to. */ @property(copy, readonly) NSString *host; + +/** + * Options of the corresponding call. Note that only the channel-related options are of interest to + * this class. + */ @property(strong, readonly) GRPCCallOptions *callOptions; +/** Acquire the factory to generate a new channel with current configurations. */ @property(readonly) id channelFactory; + +/** Acquire the dictionary of channel args with current configurations. */ @property(readonly) NSDictionary *channelArgs; - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; -- cgit v1.2.3 From dcf5f1ff384da2cf0dd6b38bb9062caed58e35c0 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 10:03:59 -0700 Subject: Comments to GRPCChannelFactory --- src/objective-c/GRPCClient/private/GRPCChannelFactory.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h index 492145da80..14dc7079ba 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h @@ -22,8 +22,10 @@ NS_ASSUME_NONNULL_BEGIN +/** A factory interface which generates new channel. */ @protocol GRPCChannelFactory + /** Create a channel with specific channel args to a specific host. */ - (nullable grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(nullable NSDictionary *)args; -- cgit v1.2.3 From 4efa40d7cda4537e42adaa0dbd70097886d2c91c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 10:06:07 -0700 Subject: Validate parameters of GRPCChannelConfiguration:initWithHost: --- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 8e0f6976cf..80fa9c9151 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -35,6 +35,8 @@ extern const char *kCFStreamVarName; @implementation GRPCChannelConfiguration - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { + NSAssert(host.length, @"Host must not be empty."); + NSAssert(callOptions, @"callOptions must not be empty."); if ((self = [super init])) { _host = [host copy]; _callOptions = [callOptions copy]; -- cgit v1.2.3 From ed1e6c48e05e510186303e430a800078128dfc89 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 12:09:19 -0700 Subject: More verbose channel destroy message --- src/objective-c/GRPCClient/private/GRPCChannel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 5fb18e0332..7151dbb6e9 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -59,8 +59,8 @@ struct grpc_channel_credentials; - (void)ref; /** - * Decrease the refcount of the channel. If the refcount of the channel decrease to 0, start a timer - * to destroy the channel + * Decrease the refcount of the channel. If the refcount of the channel decrease to 0, the channel + * is destroyed after 30 seconds. */ - (void)unref; -- cgit v1.2.3 From e667a3fb8f3465732926d44bc882dfaabc8dae54 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 12:25:25 -0700 Subject: Another copy --- src/objective-c/GRPCClient/private/GRPCChannel.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index ac4b88f304..f3ac140599 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -264,7 +264,7 @@ static GRPCChannelPool *gChannelPool; [args addEntriesFromDictionary:config.callOptions.additionalChannelArgs]; channelArgs = args; } else { - channelArgs = config.channelArgs; + channelArgs = [config.channelArgs copy]; } id factory = config.channelFactory; grpc_channel *unmanaged_channel = [factory createChannelWithHost:host channelArgs:channelArgs]; -- cgit v1.2.3 From ae99d3a5ed45e135f8b9bd9235b252fed56aa417 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 12:41:05 -0700 Subject: Document GRPCAuthorizationProtocol --- src/objective-c/GRPCClient/GRPCCallOptions.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 484f15fde6..4a93db84bc 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -57,7 +57,15 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { GRPCTransportTypeInsecure, }; +/** + * Implement this protocol to provide a token to gRPC when a call is initiated. + */ @protocol GRPCAuthorizationProtocol + +/** + * This method is called when gRPC is about to start the call. When OAuth token is acquired, + * \a handler is expected to be called with \a token being the new token to be used for this call. + */ - (void)getTokenWithHandler:(void (^)(NSString *token))hander; @end -- cgit v1.2.3 From 9a15b6a5cfa81ab31afb4945cc1ccd8fe5be5665 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 13:00:38 -0700 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.h | 16 +++++++++------- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/GRPCClient/GRPCCallOptions.h | 8 +++----- src/objective-c/GRPCClient/GRPCCallOptions.m | 14 +++++++------- src/objective-c/GRPCClient/private/ChannelArgsUtil.h | 14 +++++++++----- src/objective-c/GRPCClient/private/GRPCChannel.h | 2 +- src/objective-c/GRPCClient/private/GRPCChannel.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannelFactory.h | 2 +- src/objective-c/ProtoRPC/ProtoRPC.h | 11 ++++++----- src/objective-c/ProtoRPC/ProtoRPC.m | 11 ++++++----- src/objective-c/tests/GRPCClientTests.m | 7 ++++--- src/objective-c/tests/InteropTests.m | 7 ++++--- 12 files changed, 52 insertions(+), 44 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 13dcfa0713..b3936ad8fc 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -147,8 +147,8 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) { * Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by * the server. */ -extern NSString * const kGRPCHeadersKey; -extern NSString * const kGRPCTrailersKey; +extern NSString *const kGRPCHeadersKey; +extern NSString *const kGRPCTrailersKey; /** An object can implement this protocol to receive responses from server from a call. */ @protocol GRPCResponseHandler @@ -156,13 +156,13 @@ extern NSString * const kGRPCTrailersKey; @optional /** Issued when initial metadata is received from the server. */ -- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata; +- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; /** * Issued when a message is received from the server. The message is the raw data received from the * server, with decompression and without proto deserialization. */ -- (void)receivedRawMessage:(NSData * _Nullable)message; +- (void)receivedRawMessage:(NSData *_Nullable)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -170,7 +170,8 @@ extern NSString * const kGRPCTrailersKey; * is non-nil and contains the corresponding error information, including gRPC error codes and * error descriptions. */ -- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error; +- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata + error:(NSError *_Nullable)error; @required @@ -218,7 +219,7 @@ extern NSString * const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** * Designated initializer for a call. @@ -228,7 +229,8 @@ extern NSString * const kGRPCTrailersKey; */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler - callOptions:(GRPCCallOptions * _Nullable)callOptions NS_DESIGNATED_INITIALIZER; + callOptions:(GRPCCallOptions *_Nullable)callOptions + NS_DESIGNATED_INITIALIZER; /** * Convenience initializer for a call that uses default call options (see GRPCCallOptions.m for * the default options). diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 34a0e436ea..60a946a472 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -108,7 +108,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler - callOptions:(GRPCCallOptions * _Nullable)callOptions { + callOptions:(GRPCCallOptions *_Nullable)callOptions { if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; } diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 4a93db84bc..d1daaa1d82 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -27,14 +27,12 @@ typedef NS_ENUM(NSUInteger, GRPCCallSafety) { /** Signal that the call is idempotent. gRPC is free to use PUT verb. */ GRPCCallSafetyIdempotentRequest = 1, /** - * Signal that the call is cacheable and will not affect server state. gRPC is free to use GET - * verb. - */ + * Signal that the call is cacheable and will not affect server state. gRPC is free to use GET + * verb. + */ GRPCCallSafetyCacheableRequest = 2, }; - - // Compression algorithm to be used by a gRPC call typedef NS_ENUM(NSInteger, GRPCCompressionAlgorithm) { GRPCCompressNone = 0, diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index e148664925..fe75c17b09 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -102,7 +102,7 @@ static const NSUInteger kDefaultChannelID = 0; initialMetadata:kDefaultInitialMetadata userAgentPrefix:kDefaultUserAgentPrefix responseSizeLimit:kDefaultResponseSizeLimit - compressionAlgorithm:kDefaultCompressionAlgorithm + compressionAlgorithm:kDefaultCompressionAlgorithm enableRetry:kDefaultEnableRetry keepaliveInterval:kDefaultKeepaliveInterval keepaliveTimeout:kDefaultKeepaliveTimeout @@ -127,7 +127,7 @@ static const NSUInteger kDefaultChannelID = 0; initialMetadata:(NSDictionary *)initialMetadata userAgentPrefix:(NSString *)userAgentPrefix responseSizeLimit:(NSUInteger)responseSizeLimit - compressionAlgorithm:(GRPCCompressionAlgorithm)compressionAlgorithm + compressionAlgorithm:(GRPCCompressionAlgorithm)compressionAlgorithm enableRetry:(BOOL)enableRetry keepaliveInterval:(NSTimeInterval)keepaliveInterval keepaliveTimeout:(NSTimeInterval)keepaliveTimeout @@ -181,7 +181,7 @@ static const NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressionAlgorithm:_compressionAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout @@ -209,7 +209,7 @@ static const NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressionAlgorithm:_compressionAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout @@ -326,7 +326,7 @@ static const NSUInteger kDefaultChannelID = 0; initialMetadata:kDefaultInitialMetadata userAgentPrefix:kDefaultUserAgentPrefix responseSizeLimit:kDefaultResponseSizeLimit - compressionAlgorithm:kDefaultCompressionAlgorithm + compressionAlgorithm:kDefaultCompressionAlgorithm enableRetry:kDefaultEnableRetry keepaliveInterval:kDefaultKeepaliveInterval keepaliveTimeout:kDefaultKeepaliveTimeout @@ -353,7 +353,7 @@ static const NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressionAlgorithm:_compressionAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout @@ -381,7 +381,7 @@ static const NSUInteger kDefaultChannelID = 0; initialMetadata:_initialMetadata userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit - compressionAlgorithm:_compressionAlgorithm + compressionAlgorithm:_compressionAlgorithm enableRetry:_enableRetry keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.h b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h index 3fb876ecc4..f271e846f0 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.h +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h @@ -24,11 +24,15 @@ void GRPCFreeChannelArgs(grpc_channel_args* channel_args); /** - * Allocates a @c grpc_channel_args and populates it with the options specified in the - * @c dictionary. Keys must be @c NSString, @c NSNumber, or a pointer. If the value responds to - * @c @selector(UTF8String) then it will be mapped to @c GRPC_ARG_STRING. If the value responds to - * @c @selector(intValue), it will be mapped to @c GRPC_ARG_INTEGER. Otherwise, if the value is not - * nil, it is mapped as a pointer. The caller of this function is responsible for calling + * Allocates a @c grpc_channel_args and populates it with the options specified + * in the + * @c dictionary. Keys must be @c NSString, @c NSNumber, or a pointer. If the + * value responds to + * @c @selector(UTF8String) then it will be mapped to @c GRPC_ARG_STRING. If the + * value responds to + * @c @selector(intValue), it will be mapped to @c GRPC_ARG_INTEGER. Otherwise, + * if the value is not nil, it is mapped as a pointer. The caller of this + * function is responsible for calling * @c GRPCFreeChannelArgs to free the @c grpc_channel_args struct. */ grpc_channel_args* GRPCBuildChannelArgs(NSDictionary* dictionary); diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 7151dbb6e9..e1bf8fb1af 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -32,7 +32,7 @@ struct grpc_channel_credentials; - (nullable instancetype)init NS_UNAVAILABLE; -+ (nullable instancetype)new NS_UNAVAILABLE; ++ (nullable instancetype) new NS_UNAVAILABLE; /** * Returns a channel connecting to \a host with options as \a callOptions. The channel may be new diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index f3ac140599..018ed28a7a 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -222,7 +222,7 @@ static GRPCChannelPool *gChannelPool; }); } -- (nullable instancetype)initWithUnmanagedChannel:(grpc_channel * _Nullable)unmanagedChannel +- (nullable instancetype)initWithUnmanagedChannel:(grpc_channel *_Nullable)unmanagedChannel configuration:(GRPCChannelConfiguration *)configuration { NSAssert(configuration, @"Configuration must not be empty."); if (!unmanagedChannel) { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h index 14dc7079ba..a934e966e9 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN /** A factory interface which generates new channel. */ @protocol GRPCChannelFactory - /** Create a channel with specific channel args to a specific host. */ +/** Create a channel with specific channel args to a specific host. */ - (nullable grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(nullable NSDictionary *)args; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 3a7fd58fb1..960a9a12bd 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -31,12 +31,12 @@ NS_ASSUME_NONNULL_BEGIN @optional /** Issued when initial metadata is received from the server. */ -- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata; +- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; /** * Issued when a message is received from the server. The message is the deserialized proto object. */ -- (void)receivedProtoMessage:(GPBMessage * _Nullable)message; +- (void)receivedProtoMessage:(GPBMessage *_Nullable)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -44,7 +44,8 @@ NS_ASSUME_NONNULL_BEGIN * is non-nil and contains the corresponding error information, including gRPC error codes and * error descriptions. */ -- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error; +- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata + error:(NSError *_Nullable)error; @required @@ -70,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message responseHandler:(id)handler - callOptions:(GRPCCallOptions * _Nullable)callOptions + callOptions:(GRPCCallOptions *_Nullable)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** @@ -95,7 +96,7 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)handler - callOptions:(GRPCCallOptions * _Nullable)callOptions + callOptions:(GRPCCallOptions *_Nullable)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index f6e3298f62..28c037e609 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -34,7 +34,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message responseHandler:(id)handler - callOptions:(GRPCCallOptions * _Nullable)callOptions + callOptions:(GRPCCallOptions *_Nullable)callOptions responseClass:(Class)responseClass { if ((self = [super init])) { _call = [[GRPCStreamingProtoCall alloc] initWithRequestOptions:requestOptions @@ -70,7 +70,7 @@ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)handler - callOptions:(GRPCCallOptions * _Nullable)callOptions + callOptions:(GRPCCallOptions *_Nullable)callOptions responseClass:(Class)responseClass { if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; @@ -153,7 +153,7 @@ }); } -- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { if (_handler && initialMetadata != nil) { id handler = _handler; if ([handler respondsToSelector:@selector(initialMetadata:)]) { @@ -164,7 +164,7 @@ } } -- (void)receivedRawMessage:(NSData * _Nullable)message { +- (void)receivedRawMessage:(NSData *_Nullable)message { if (_handler && message != nil) { id handler = _handler; NSError *error = nil; @@ -188,7 +188,8 @@ } } -- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error { +- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata + error:(NSError *_Nullable)error { if (_handler) { id handler = _handler; if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 0a9ec97c48..0d1b80e33c 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -114,19 +114,20 @@ static GRPCProtoMethod *kFullDuplexCallMethod; return self; } -- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { if (_initialMetadataCallback) { _initialMetadataCallback(initialMetadata); } } -- (void)receivedProtoMessage:(GPBMessage * _Nullable)message { +- (void)receivedProtoMessage:(GPBMessage *_Nullable)message { if (_messageCallback) { _messageCallback(message); } } -- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error { +- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata + error:(NSError *_Nullable)error { if (_closeCallback) { _closeCallback(trailingMetadata, error); } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index fb49bb99e0..d67dc0743e 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -102,19 +102,20 @@ BOOL isRemoteInteropTest(NSString *host) { return self; } -- (void)receivedInitialMetadata:(NSDictionary * _Nullable)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { if (_initialMetadataCallback) { _initialMetadataCallback(initialMetadata); } } -- (void)receivedProtoMessage:(GPBMessage * _Nullable)message { +- (void)receivedProtoMessage:(GPBMessage *_Nullable)message { if (_messageCallback) { _messageCallback(message); } } -- (void)closedWithTrailingMetadata:(NSDictionary * _Nullable)trailingMetadata error:(NSError * _Nullable)error { +- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata + error:(NSError *_Nullable)error { if (_closeCallback) { _closeCallback(trailingMetadata, error); } -- cgit v1.2.3 From 2b0470dcb3bd8306adb1c63a81c931482e86c5fa Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sat, 20 Oct 2018 13:07:02 -0700 Subject: Ignore serverAuthority when using Cronet transport --- src/objective-c/GRPCClient/private/GRPCChannel.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 018ed28a7a..60c2e29a6e 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -161,7 +161,8 @@ static GRPCChannelPool *gChannelPool; __block grpc_call *call = nil; dispatch_sync(_dispatchQueue, ^{ if (self->_unmanagedChannel) { - NSString *serverAuthority = callOptions.serverAuthority; + NSString *serverAuthority = + callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; NSAssert(timeout >= 0, @"Invalid timeout"); grpc_slice host_slice = grpc_empty_slice(); -- cgit v1.2.3 From 5c7ab989bed8e8b757db0de077571eeec66d3f2f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 22 Oct 2018 11:13:39 -0700 Subject: bool->BOOL --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 60a946a472..7e0640e8ae 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -103,7 +103,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; /** Serial dispatch queue for tasks inside the call. */ dispatch_queue_t _dispatchQueue; /** Flags whether call has started. */ - bool _started; + BOOL _started; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions -- cgit v1.2.3 From b03adfbf067cc4f7ef05eb7fa8cbf49c08b3bf6b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 22 Oct 2018 12:14:43 -0700 Subject: More nullability specifier --- src/objective-c/GRPCClient/GRPCCall.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index b3936ad8fc..2f23b879f1 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -304,7 +304,7 @@ NS_ASSUME_NONNULL_END * * The property is initialized to an empty NSMutableDictionary. */ -@property(atomic, readonly) NSMutableDictionary *requestHeaders; +@property(null_unspecified, atomic, readonly) NSMutableDictionary * requestHeaders; /** * This dictionary is populated with the HTTP headers received from the server. This happens before @@ -315,7 +315,7 @@ NS_ASSUME_NONNULL_END * The value of this property is nil until all response headers are received, and will change before * any of -writeValue: or -writesFinishedWithError: are sent to the writeable. */ -@property(atomic, readonly) NSDictionary *responseHeaders; +@property(null_unspecified, atomic, readonly) NSDictionary *responseHeaders; /** * Same as responseHeaders, but populated with the HTTP trailers received from the server before the @@ -324,7 +324,7 @@ NS_ASSUME_NONNULL_END * The value of this property is nil until all response trailers are received, and will change * before -writesFinishedWithError: is sent to the writeable. */ -@property(atomic, readonly) NSDictionary *responseTrailers; +@property(null_unspecified, atomic, readonly) NSDictionary *responseTrailers; /** * The request writer has to write NSData objects into the provided Writeable. The server will @@ -337,9 +337,9 @@ NS_ASSUME_NONNULL_END * host parameter should not contain the scheme (http:// or https://), only the name or IP addr * and the port number, for example @"localhost:5050". */ -- (instancetype)initWithHost:(NSString *)host - path:(NSString *)path - requestsWriter:(GRXWriter *)requestWriter; +- (instancetype _Null_unspecified)initWithHost:(NSString * _Null_unspecified)host + path:(NSString * _Null_unspecified)path + requestsWriter:(GRXWriter * _Null_unspecified)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and @@ -350,10 +350,10 @@ NS_ASSUME_NONNULL_END /** * The following methods are deprecated. */ -+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; -@property(atomic, copy, readwrite) NSString *serverName; ++ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString * _Null_unspecified)host path:(NSString * _Null_unspecified)path; +@property(null_unspecified, atomic, copy, readwrite) NSString *serverName; @property NSTimeInterval timeout; -- (void)setResponseDispatchQueue:(dispatch_queue_t)queue; +- (void)setResponseDispatchQueue:(dispatch_queue_t _Null_unspecified)queue; @end @@ -364,11 +364,11 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; -- (id)objectForKeyedSubscript:(id)key; -- (void)setObject:(id)obj forKeyedSubscript:(id)key; +- (id _Null_unspecified)objectForKeyedSubscript:(id _Null_unspecified)key; +- (void)setObject:(id _Null_unspecified)obj forKeyedSubscript:(id _Null_unspecified)key; - (void)removeAllObjects; -- (void)removeObjectForKey:(id)key; +- (void)removeObjectForKey:(id _Null_unspecified)key; @end #pragma clang diagnostic push -- cgit v1.2.3 From fb1ebfef00e5153e30c1a008a350c53dde4335c3 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 22 Oct 2018 13:56:10 -0700 Subject: Fix test flake --- src/objective-c/tests/GRPCClientTests.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 0d1b80e33c..2021540f28 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -120,7 +120,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } } -- (void)receivedProtoMessage:(GPBMessage *_Nullable)message { +- (void)receivedRawMessage:(GPBMessage *_Nullable)message { if (_messageCallback) { _messageCallback(message); } @@ -803,7 +803,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; NSString *const kDummyAddress = [NSString stringWithFormat:@"8.8.8.8:1"]; GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress - path:@"" + path:@"/dummyPath" requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; [GRPCCall setMinConnectTimeout:timeout * 1000 initialBackoff:backoff * 1000 -- cgit v1.2.3 From 3566540f16451ea87aff980b5de13c41a8debeb6 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 22 Oct 2018 14:45:38 -0700 Subject: nit: group includes --- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 41d3bec4ef..c0d75c0f31 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -20,11 +20,11 @@ #import #import +#import #include #include -#import #import "GRPCChannelFactory.h" #import "GRPCCompletionQueue.h" #import "GRPCConnectivityMonitor.h" -- cgit v1.2.3 From e13c8678264d85353bb2ce49ae829c03f6c9493f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 22 Oct 2018 18:25:16 -0700 Subject: Do not issue more message when the call is canceled --- src/objective-c/GRPCClient/GRPCCall.m | 61 ++++++++++++++++++++++++++--------- src/objective-c/ProtoRPC/ProtoRPC.m | 43 ++++++++++++++++++------ 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 7e0640e8ae..23c8d0f2d7 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -104,6 +104,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_queue_t _dispatchQueue; /** Flags whether call has started. */ BOOL _started; + /** + * Flags that the call has been canceled. When this is true, pending initial metadata and message + * should not be issued to \a _handler. This ivar must be accessed with lock to self. + */ + BOOL _canceled; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -135,6 +140,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); _started = NO; + _canceled = NO; } return self; @@ -217,6 +223,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; self->_pipe = nil; } if (self->_handler) { + @synchronized(self) { + self->_canceled = YES; + } id handler = self->_handler; dispatch_async(handler.dispatchQueue, ^{ if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { @@ -252,30 +261,50 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { - id handler = _handler; - if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:initialMetadata]; - }); + if (_handler != nil && initialMetadata != nil) { + id handler = _handler; + if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + dispatch_async(handler.dispatchQueue, ^{ + // Do not issue initial metadata if the call is already canceled. + __block BOOL canceled = NO; + @synchronized(self) { + canceled = self->_canceled; + } + if (!canceled) { + [handler receivedInitialMetadata:initialMetadata]; + } + }); + } } } - (void)issueMessage:(id)message { - id handler = _handler; - if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedRawMessage:message]; - }); + if (_handler != nil && message != nil) { + id handler = _handler; + if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { + dispatch_async(handler.dispatchQueue, ^{ + // Do not issue message if the call is already canceled. + __block BOOL canceled = NO; + @synchronized(self) { + canceled = self->_canceled; + } + if (!canceled) { + [handler receivedRawMessage:message]; + } + }); + } } } - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - id handler = _handler; - NSDictionary *trailers = _call.responseTrailers; - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:trailers error:error]; - }); + if (_handler != nil) { + id handler = _handler; + NSDictionary *trailers = _call.responseTrailers; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:trailers error:error]; + }); + } } } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 28c037e609..a6c88488fc 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -66,6 +66,11 @@ GRPCCall2 *_call; dispatch_queue_t _dispatchQueue; + /** + * Flags that the call has been canceled. When this is true, pending initial metadata and message + * should not be issued to \a _handler. This ivar must be accessed with lock to self. + */ + BOOL _canceled; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -95,6 +100,7 @@ _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); } dispatch_set_target_queue(handler.dispatchQueue, _dispatchQueue); + _canceled = NO; [self start]; } @@ -110,12 +116,15 @@ - (void)cancel { dispatch_async(_dispatchQueue, ^{ - if (_call) { - [_call cancel]; - _call = nil; + if (self->_call) { + [self->_call cancel]; + self->_call = nil; } - if (_handler) { - id handler = _handler; + if (self->_handler) { + @synchronized(self) { + self->_canceled = YES; + } + id handler = self->_handler; if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(handler.dispatchQueue, ^{ [handler closedWithTrailingMetadata:nil @@ -127,7 +136,7 @@ }]]; }); } - _handler = nil; + self->_handler = nil; } }); } @@ -155,10 +164,17 @@ - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { if (_handler && initialMetadata != nil) { - id handler = _handler; + __block id handler = _handler; if ([handler respondsToSelector:@selector(initialMetadata:)]) { dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:initialMetadata]; + // Do not issue initial metadata if the call is already canceled. + __block BOOL canceled = NO; + @synchronized(self) { + canceled = self->_canceled; + } + if (!canceled) { + [handler receivedInitialMetadata:initialMetadata]; + } }); } } @@ -166,13 +182,20 @@ - (void)receivedRawMessage:(NSData *_Nullable)message { if (_handler && message != nil) { - id handler = _handler; + __block id handler = _handler; NSError *error = nil; GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; if (parsed) { if ([handler respondsToSelector:@selector(receivedProtoMessage:)]) { dispatch_async(handler.dispatchQueue, ^{ - [handler receivedProtoMessage:parsed]; + // Do not issue message if the call is already canceled. + __block BOOL canceled = NO; + @synchronized(self) { + canceled = self->_canceled; + } + if (!canceled) { + [handler receivedProtoMessage:parsed]; + } }); } } else { -- cgit v1.2.3 From 76ddfcb6cb87611addcbc68b01264e37a4705d27 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 22 Oct 2018 18:36:59 -0700 Subject: Propagate internal error when failed parsing proto --- src/objective-c/ProtoRPC/ProtoRPC.m | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index a6c88488fc..6085f89356 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -27,6 +27,24 @@ #import #import +/** + * Generate an NSError object that represents a failure in parsing a proto class. + */ +static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { + NSDictionary *info = @{ + NSLocalizedDescriptionKey : @"Unable to parse response from the server", + NSLocalizedRecoverySuggestionErrorKey : + @"If this RPC is idempotent, retry " + @"with exponential backoff. Otherwise, query the server status before " + @"retrying.", + NSUnderlyingErrorKey : parsingError, + @"Expected class" : expectedClass, + @"Received value" : proto, + }; + // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public. + return [NSError errorWithDomain:@"io.grpc" code:13 userInfo:info]; +} + @implementation GRPCUnaryProtoCall { GRPCStreamingProtoCall *_call; } @@ -201,7 +219,7 @@ } else { if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:nil error:error]; + [handler closedWithTrailingMetadata:nil error:ErrorForBadProto(message, _responseClass, error)]; }); } _handler = nil; @@ -232,21 +250,6 @@ @end -static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { - NSDictionary *info = @{ - NSLocalizedDescriptionKey : @"Unable to parse response from the server", - NSLocalizedRecoverySuggestionErrorKey : - @"If this RPC is idempotent, retry " - @"with exponential backoff. Otherwise, query the server status before " - @"retrying.", - NSUnderlyingErrorKey : parsingError, - @"Expected class" : expectedClass, - @"Received value" : proto, - }; - // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public. - return [NSError errorWithDomain:@"io.grpc" code:13 userInfo:info]; -} - #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-implementations" @implementation ProtoRPC { -- cgit v1.2.3 From e39c146f0f7f1a56e0cd65ec5d707c8bb091366e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 10:03:48 -0700 Subject: Revert "Do not issue more message when the call is canceled" This reverts commit e13c8678264d85353bb2ce49ae829c03f6c9493f. --- src/objective-c/GRPCClient/GRPCCall.m | 61 +++++++++-------------------------- src/objective-c/ProtoRPC/ProtoRPC.m | 43 ++++++------------------ 2 files changed, 26 insertions(+), 78 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 23c8d0f2d7..7e0640e8ae 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -104,11 +104,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_queue_t _dispatchQueue; /** Flags whether call has started. */ BOOL _started; - /** - * Flags that the call has been canceled. When this is true, pending initial metadata and message - * should not be issued to \a _handler. This ivar must be accessed with lock to self. - */ - BOOL _canceled; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -140,7 +135,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; } dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); _started = NO; - _canceled = NO; } return self; @@ -223,9 +217,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; self->_pipe = nil; } if (self->_handler) { - @synchronized(self) { - self->_canceled = YES; - } id handler = self->_handler; dispatch_async(handler.dispatchQueue, ^{ if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { @@ -261,50 +252,30 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { - if (_handler != nil && initialMetadata != nil) { - id handler = _handler; - if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { - dispatch_async(handler.dispatchQueue, ^{ - // Do not issue initial metadata if the call is already canceled. - __block BOOL canceled = NO; - @synchronized(self) { - canceled = self->_canceled; - } - if (!canceled) { - [handler receivedInitialMetadata:initialMetadata]; - } - }); - } + id handler = _handler; + if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedInitialMetadata:initialMetadata]; + }); } } - (void)issueMessage:(id)message { - if (_handler != nil && message != nil) { - id handler = _handler; - if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { - dispatch_async(handler.dispatchQueue, ^{ - // Do not issue message if the call is already canceled. - __block BOOL canceled = NO; - @synchronized(self) { - canceled = self->_canceled; - } - if (!canceled) { - [handler receivedRawMessage:message]; - } - }); - } + id handler = _handler; + if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler receivedRawMessage:message]; + }); } } - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - if (_handler != nil) { - id handler = _handler; - NSDictionary *trailers = _call.responseTrailers; - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:trailers error:error]; - }); - } + id handler = _handler; + NSDictionary *trailers = _call.responseTrailers; + if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(handler.dispatchQueue, ^{ + [handler closedWithTrailingMetadata:trailers error:error]; + }); } } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 6085f89356..294f3a4cf5 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -84,11 +84,6 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing GRPCCall2 *_call; dispatch_queue_t _dispatchQueue; - /** - * Flags that the call has been canceled. When this is true, pending initial metadata and message - * should not be issued to \a _handler. This ivar must be accessed with lock to self. - */ - BOOL _canceled; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -118,7 +113,6 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); } dispatch_set_target_queue(handler.dispatchQueue, _dispatchQueue); - _canceled = NO; [self start]; } @@ -134,15 +128,12 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (void)cancel { dispatch_async(_dispatchQueue, ^{ - if (self->_call) { - [self->_call cancel]; - self->_call = nil; + if (_call) { + [_call cancel]; + _call = nil; } - if (self->_handler) { - @synchronized(self) { - self->_canceled = YES; - } - id handler = self->_handler; + if (_handler) { + id handler = _handler; if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(handler.dispatchQueue, ^{ [handler closedWithTrailingMetadata:nil @@ -154,7 +145,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing }]]; }); } - self->_handler = nil; + _handler = nil; } }); } @@ -182,17 +173,10 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { if (_handler && initialMetadata != nil) { - __block id handler = _handler; + id handler = _handler; if ([handler respondsToSelector:@selector(initialMetadata:)]) { dispatch_async(handler.dispatchQueue, ^{ - // Do not issue initial metadata if the call is already canceled. - __block BOOL canceled = NO; - @synchronized(self) { - canceled = self->_canceled; - } - if (!canceled) { - [handler receivedInitialMetadata:initialMetadata]; - } + [handler receivedInitialMetadata:initialMetadata]; }); } } @@ -200,20 +184,13 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (void)receivedRawMessage:(NSData *_Nullable)message { if (_handler && message != nil) { - __block id handler = _handler; + id handler = _handler; NSError *error = nil; GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; if (parsed) { if ([handler respondsToSelector:@selector(receivedProtoMessage:)]) { dispatch_async(handler.dispatchQueue, ^{ - // Do not issue message if the call is already canceled. - __block BOOL canceled = NO; - @synchronized(self) { - canceled = self->_canceled; - } - if (!canceled) { - [handler receivedProtoMessage:parsed]; - } + [handler receivedProtoMessage:parsed]; }); } } else { -- cgit v1.2.3 From f3e9224f0b34a6265830600c67293d96964a4c5c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 10:22:18 -0700 Subject: Remove retain of handler in callbacks and dispatch to dispatchQueue --- src/objective-c/GRPCClient/GRPCCall.h | 11 ++++-- src/objective-c/GRPCClient/GRPCCall.m | 21 ++++------- src/objective-c/ProtoRPC/ProtoRPC.h | 8 +++-- src/objective-c/ProtoRPC/ProtoRPC.m | 63 ++++++++++++++------------------- src/objective-c/tests/GRPCClientTests.m | 24 ++++++++----- src/objective-c/tests/InteropTests.m | 24 ++++++++----- 6 files changed, 77 insertions(+), 74 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 2f23b879f1..85d0a302d1 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -155,12 +155,16 @@ extern NSString *const kGRPCTrailersKey; @optional -/** Issued when initial metadata is received from the server. */ +/** + * Issued when initial metadata is received from the server. The task must be scheduled onto the + * dispatch queue in property \a dispatchQueue. + */ - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; /** * Issued when a message is received from the server. The message is the raw data received from the - * server, with decompression and without proto deserialization. + * server, with decompression and without proto deserialization. The task must be scheduled onto the + * dispatch queue in property \a dispatchQueue. */ - (void)receivedRawMessage:(NSData *_Nullable)message; @@ -168,7 +172,8 @@ extern NSString *const kGRPCTrailersKey; * Issued when a call finished. If the call finished successfully, \a error is nil and \a * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error * is non-nil and contains the corresponding error information, including gRPC error codes and - * error descriptions. + * error descriptions. The task must be scheduled onto the dispatch queue in property + * \a dispatchQueue. */ - (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata error:(NSError *_Nullable)error; diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 7e0640e8ae..29a0ed4e10 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -252,30 +252,21 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { - id handler = _handler; - if ([handler respondsToSelector:@selector(receivedInitialMetadata:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:initialMetadata]; - }); + if (initialMetadata != nil && [_handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + [_handler receivedInitialMetadata:initialMetadata]; } } - (void)issueMessage:(id)message { - id handler = _handler; - if ([handler respondsToSelector:@selector(receivedRawMessage:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedRawMessage:message]; - }); + if (message != nil && [_handler respondsToSelector:@selector(receivedRawMessage:)]) { + [_handler receivedRawMessage:message]; } } - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - id handler = _handler; NSDictionary *trailers = _call.responseTrailers; - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:trailers error:error]; - }); + if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + [_handler closedWithTrailingMetadata:trailers error:error]; } } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 960a9a12bd..6f4b9eed75 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -30,11 +30,14 @@ NS_ASSUME_NONNULL_BEGIN @optional -/** Issued when initial metadata is received from the server. */ +/** + * Issued when initial metadata is received from the server. The task must be scheduled onto the + * dispatch queue in property \a dispatchQueue. */ - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; /** * Issued when a message is received from the server. The message is the deserialized proto object. + * The task must be scheduled onto the dispatch queue in property \a dispatchQueue. */ - (void)receivedProtoMessage:(GPBMessage *_Nullable)message; @@ -42,7 +45,8 @@ NS_ASSUME_NONNULL_BEGIN * Issued when a call finished. If the call finished successfully, \a error is nil and \a * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error * is non-nil and contains the corresponding error information, including gRPC error codes and - * error descriptions. + * error descriptions. The task must be scheduled onto the dispatch queue in property + * \a dispatchQueue. */ - (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata error:(NSError *_Nullable)error; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 294f3a4cf5..27070a891d 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -172,53 +172,44 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { - if (_handler && initialMetadata != nil) { - id handler = _handler; - if ([handler respondsToSelector:@selector(initialMetadata:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedInitialMetadata:initialMetadata]; - }); + dispatch_async(_dispatchQueue, ^{ + if (initialMetadata != nil && [self->_handler respondsToSelector:@selector(initialMetadata:)]) { + [self->_handler receivedInitialMetadata:initialMetadata]; } - } + }); } - (void)receivedRawMessage:(NSData *_Nullable)message { - if (_handler && message != nil) { - id handler = _handler; - NSError *error = nil; - GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; - if (parsed) { - if ([handler respondsToSelector:@selector(receivedProtoMessage:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler receivedProtoMessage:parsed]; - }); - } - } else { - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:nil error:ErrorForBadProto(message, _responseClass, error)]; - }); + dispatch_async(_dispatchQueue, ^{ + if (self->_handler && message != nil) { + NSError *error = nil; + GPBMessage *parsed = [self->_responseClass parseFromData:message error:&error]; + if (parsed) { + if ([self->_handler respondsToSelector:@selector(receivedProtoMessage:)]) { + [self->_handler receivedProtoMessage:parsed]; + } + } else { + if ([self->_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + [self->_handler closedWithTrailingMetadata:nil error:ErrorForBadProto(message, _responseClass, error)]; + } + self->_handler = nil; + [self->_call cancel]; + self->_call = nil; } - _handler = nil; - [_call cancel]; - _call = nil; } - } + }); } - (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata error:(NSError *_Nullable)error { - if (_handler) { - id handler = _handler; - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - dispatch_async(handler.dispatchQueue, ^{ - [handler closedWithTrailingMetadata:trailingMetadata error:error]; - }); + dispatch_async(_dispatchQueue, ^{ + if ([self->_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + [self->_handler closedWithTrailingMetadata:trailingMetadata error:error]; } - _handler = nil; - } - [_call cancel]; - _call = nil; + self->_handler = nil; + [self->_call cancel]; + self->_call = nil; + }); } - (dispatch_queue_t)dispatchQueue { diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 2021540f28..bbe81502dc 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -115,22 +115,28 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { - if (_initialMetadataCallback) { - _initialMetadataCallback(initialMetadata); - } + dispatch_async(_dispatchQueue, ^{ + if (_initialMetadataCallback) { + _initialMetadataCallback(initialMetadata); + } + }); } - (void)receivedRawMessage:(GPBMessage *_Nullable)message { - if (_messageCallback) { - _messageCallback(message); - } + dispatch_async(_dispatchQueue, ^{ + if (_messageCallback) { + _messageCallback(message); + } + }); } - (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata error:(NSError *_Nullable)error { - if (_closeCallback) { - _closeCallback(trailingMetadata, error); - } + dispatch_async(_dispatchQueue, ^{ + if (_closeCallback) { + _closeCallback(trailingMetadata, error); + } + }); } - (dispatch_queue_t)dispatchQueue { diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index d67dc0743e..c42718f15e 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -103,22 +103,28 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { - if (_initialMetadataCallback) { - _initialMetadataCallback(initialMetadata); - } + dispatch_async(_dispatchQueue, ^{ + if (_initialMetadataCallback) { + _initialMetadataCallback(initialMetadata); + } + }); } - (void)receivedProtoMessage:(GPBMessage *_Nullable)message { - if (_messageCallback) { - _messageCallback(message); - } + dispatch_async(_dispatchQueue, ^{ + if (_messageCallback) { + _messageCallback(message); + } + }); } - (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata error:(NSError *_Nullable)error { - if (_closeCallback) { - _closeCallback(trailingMetadata, error); - } + dispatch_async(_dispatchQueue, ^{ + if (_closeCallback) { + _closeCallback(trailingMetadata, error); + } + }); } - (dispatch_queue_t)dispatchQueue { -- cgit v1.2.3 From 351b5d0f13138690b8ce75a7675306caec5c9e62 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 10:28:04 -0700 Subject: enableRetry->retryEnabled --- src/objective-c/GRPCClient/GRPCCallOptions.h | 4 +-- src/objective-c/GRPCClient/GRPCCallOptions.m | 32 +++++++++++----------- .../GRPCClient/private/GRPCChannelPool.m | 4 +-- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index d1daaa1d82..4c8bb605ea 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -132,7 +132,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * refer to * https://github.com/grpc/proposal/blob/master/A6-client-retries.md */ -@property(readonly) BOOL enableRetry; +@property(readonly) BOOL retryEnabled; // HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two // PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the @@ -279,7 +279,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * refer to * https://github.com/grpc/proposal/blob/master/A6-client-retries.md */ -@property(readwrite) BOOL enableRetry; +@property(readwrite) BOOL retryEnabled; // HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two // PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index fe75c17b09..85a5a9ac89 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -25,7 +25,7 @@ static NSDictionary *const kDefaultInitialMetadata = nil; static NSString *const kDefaultUserAgentPrefix = nil; static const NSUInteger kDefaultResponseSizeLimit = 0; static const GRPCCompressionAlgorithm kDefaultCompressionAlgorithm = GRPCCompressNone; -static const BOOL kDefaultEnableRetry = YES; +static const BOOL kDefaultRetryEnabled = YES; static const NSTimeInterval kDefaultKeepaliveInterval = 0; static const NSTimeInterval kDefaultKeepaliveTimeout = 0; static const NSTimeInterval kDefaultConnectMinTimeout = 0; @@ -53,7 +53,7 @@ static const NSUInteger kDefaultChannelID = 0; NSString *_userAgentPrefix; NSUInteger _responseSizeLimit; GRPCCompressionAlgorithm _compressionAlgorithm; - BOOL _enableRetry; + BOOL _retryEnabled; NSTimeInterval _keepaliveInterval; NSTimeInterval _keepaliveTimeout; NSTimeInterval _connectMinTimeout; @@ -78,7 +78,7 @@ static const NSUInteger kDefaultChannelID = 0; @synthesize userAgentPrefix = _userAgentPrefix; @synthesize responseSizeLimit = _responseSizeLimit; @synthesize compressionAlgorithm = _compressionAlgorithm; -@synthesize enableRetry = _enableRetry; +@synthesize retryEnabled = _retryEnabled; @synthesize keepaliveInterval = _keepaliveInterval; @synthesize keepaliveTimeout = _keepaliveTimeout; @synthesize connectMinTimeout = _connectMinTimeout; @@ -103,7 +103,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:kDefaultUserAgentPrefix responseSizeLimit:kDefaultResponseSizeLimit compressionAlgorithm:kDefaultCompressionAlgorithm - enableRetry:kDefaultEnableRetry + retryEnabled:kDefaultRetryEnabled keepaliveInterval:kDefaultKeepaliveInterval keepaliveTimeout:kDefaultKeepaliveTimeout connectMinTimeout:kDefaultConnectMinTimeout @@ -128,7 +128,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:(NSString *)userAgentPrefix responseSizeLimit:(NSUInteger)responseSizeLimit compressionAlgorithm:(GRPCCompressionAlgorithm)compressionAlgorithm - enableRetry:(BOOL)enableRetry + retryEnabled:(BOOL)retryEnabled keepaliveInterval:(NSTimeInterval)keepaliveInterval keepaliveTimeout:(NSTimeInterval)keepaliveTimeout connectMinTimeout:(NSTimeInterval)connectMinTimeout @@ -152,7 +152,7 @@ static const NSUInteger kDefaultChannelID = 0; _userAgentPrefix = [userAgentPrefix copy]; _responseSizeLimit = responseSizeLimit; _compressionAlgorithm = compressionAlgorithm; - _enableRetry = enableRetry; + _retryEnabled = retryEnabled; _keepaliveInterval = keepaliveInterval; _keepaliveTimeout = keepaliveTimeout; _connectMinTimeout = connectMinTimeout; @@ -182,7 +182,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - enableRetry:_enableRetry + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout @@ -210,7 +210,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - enableRetry:_enableRetry + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout @@ -234,7 +234,7 @@ static const NSUInteger kDefaultChannelID = 0; return NO; if (!(callOptions.responseSizeLimit == _responseSizeLimit)) return NO; if (!(callOptions.compressionAlgorithm == _compressionAlgorithm)) return NO; - if (!(callOptions.enableRetry == _enableRetry)) return NO; + if (!(callOptions.retryEnabled == _retryEnabled)) return NO; if (!(callOptions.keepaliveInterval == _keepaliveInterval)) return NO; if (!(callOptions.keepaliveTimeout == _keepaliveTimeout)) return NO; if (!(callOptions.connectMinTimeout == _connectMinTimeout)) return NO; @@ -271,7 +271,7 @@ static const NSUInteger kDefaultChannelID = 0; result ^= _userAgentPrefix.hash; result ^= _responseSizeLimit; result ^= _compressionAlgorithm; - result ^= _enableRetry; + result ^= _retryEnabled; result ^= (unsigned int)(_keepaliveInterval * 1000); result ^= (unsigned int)(_keepaliveTimeout * 1000); result ^= (unsigned int)(_connectMinTimeout * 1000); @@ -302,7 +302,7 @@ static const NSUInteger kDefaultChannelID = 0; @dynamic userAgentPrefix; @dynamic responseSizeLimit; @dynamic compressionAlgorithm; -@dynamic enableRetry; +@dynamic retryEnabled; @dynamic keepaliveInterval; @dynamic keepaliveTimeout; @dynamic connectMinTimeout; @@ -327,7 +327,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:kDefaultUserAgentPrefix responseSizeLimit:kDefaultResponseSizeLimit compressionAlgorithm:kDefaultCompressionAlgorithm - enableRetry:kDefaultEnableRetry + retryEnabled:kDefaultRetryEnabled keepaliveInterval:kDefaultKeepaliveInterval keepaliveTimeout:kDefaultKeepaliveTimeout connectMinTimeout:kDefaultConnectMinTimeout @@ -354,7 +354,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - enableRetry:_enableRetry + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout @@ -382,7 +382,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - enableRetry:_enableRetry + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout @@ -436,8 +436,8 @@ static const NSUInteger kDefaultChannelID = 0; _compressionAlgorithm = compressionAlgorithm; } -- (void)setEnableRetry:(BOOL)enableRetry { - _enableRetry = enableRetry; +- (void)setRetryEnabled:(BOOL)retryEnabled { + _retryEnabled = retryEnabled; } - (void)setKeepaliveInterval:(NSTimeInterval)keepaliveInterval { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 80fa9c9151..1dfae32342 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -108,8 +108,8 @@ extern const char *kCFStreamVarName; [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.keepaliveTimeout * 1000)]; } - if (_callOptions.enableRetry == NO) { - args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:_callOptions.enableRetry]; + if (_callOptions.retryEnabled == NO) { + args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:_callOptions.retryEnabled]; } if (_callOptions.connectMinTimeout > 0) { diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index c0d75c0f31..38b31c2ebc 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -103,7 +103,7 @@ static NSMutableDictionary *gHostCache; options.userAgentPrefix = _userAgentPrefix; options.responseSizeLimit = _responseSizeLimitOverride; options.compressionAlgorithm = (GRPCCompressionAlgorithm)_compressAlgorithm; - options.enableRetry = _retryEnabled; + options.retryEnabled = _retryEnabled; options.keepaliveInterval = (NSTimeInterval)_keepaliveInterval / 1000; options.keepaliveTimeout = (NSTimeInterval)_keepaliveTimeout / 1000; options.connectMinTimeout = (NSTimeInterval)_minConnectTimeout / 1000; -- cgit v1.2.3 From 8986cfe6259fe7efc6ad438abb9e904f190c0515 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 10:39:39 -0700 Subject: Assert mutual exclusion of authTokenProvider and oauth2AccessToken --- src/objective-c/GRPCClient/GRPCCall.m | 3 +++ src/objective-c/GRPCClient/GRPCCallOptions.h | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 29a0ed4e10..85a2837336 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -781,6 +781,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; } _callOptions = callOptions; } + + NSAssert(_callOptions.authTokenProvider != nil || _callOptions.oauth2AccessToken != nil, + @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); if (_callOptions.authTokenProvider != nil) { @synchronized(self) { self.isWaitingForToken = YES; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 4c8bb605ea..27834b2008 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -91,8 +91,8 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * The OAuth2 access token string. The string is prefixed with "Bearer " then used as value of the - * request's "authorization" header field. This parameter takes precedence over \a - * oauth2AccessToken. + * request's "authorization" header field. This parameter should not be used simultaneously with + * \a authTokenProvider. */ @property(copy, readonly) NSString *oauth2AccessToken; @@ -245,7 +245,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when - * initiating the call. This parameter takes precedence over \a oauth2AccessToken. + * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken. */ @property(readwrite) id authTokenProvider; -- cgit v1.2.3 From 3c8e9886aca311ee2b26e7f7ef827ac7efb42716 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 10:53:11 -0700 Subject: Mark channelArg as copy --- src/objective-c/GRPCClient/private/GRPCChannel.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 60c2e29a6e..777cbab809 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -265,7 +265,7 @@ static GRPCChannelPool *gChannelPool; [args addEntriesFromDictionary:config.callOptions.additionalChannelArgs]; channelArgs = args; } else { - channelArgs = [config.channelArgs copy]; + channelArgs = config.channelArgs; } id factory = config.channelFactory; grpc_channel *unmanaged_channel = [factory createChannelWithHost:host channelArgs:channelArgs]; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 43e07b9845..2244361df2 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -45,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN @property(readonly) id channelFactory; /** Acquire the dictionary of channel args with current configurations. */ -@property(readonly) NSDictionary *channelArgs; +@property(copy, readonly) NSDictionary *channelArgs; - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; -- cgit v1.2.3 From 647e24c190465e9547583a631ac5b33de98ae812 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 11:31:36 -0700 Subject: Put logContext in class extension --- gRPC.podspec | 2 +- src/objective-c/GRPCClient/GRPCCallOptions.h | 10 ------ src/objective-c/GRPCClient/GRPCCallOptions.m | 1 + .../GRPCClient/internal/GRPCCallOptions+internal.h | 37 ++++++++++++++++++++++ .../GRPCClient/private/GRPCChannelPool.m | 1 + src/objective-c/GRPCClient/private/GRPCHost.m | 1 + templates/gRPC.podspec.template | 2 +- 7 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h diff --git a/gRPC.podspec b/gRPC.podspec index 5e513cb127..47a130d12d 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -58,7 +58,7 @@ Pod::Spec.new do |s| ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" ss.exclude_files = "#{src_dir}/GRPCCall+GID.{h,m}" - ss.private_header_files = "#{src_dir}/private/*.h" + ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/GRPCCallOptions+Internal.h" ss.dependency 'gRPC-Core', version end diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 27834b2008..4f02b344b1 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -182,11 +182,6 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { */ @property(copy, readonly) NSString *hostNameOverride; -/** - * Parameter used for internal logging. - */ -@property(readonly) id logContext; - /** * A string that specify the domain where channel is being cached. Channels with different domains * will not get cached to the same connection. @@ -331,11 +326,6 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { */ @property(copy, readwrite) NSString *hostNameOverride; -/** - * Parameter used for internal logging. - */ -@property(copy, readwrite) id logContext; - /** * A string that specify the domain where channel is being cached. Channels with different domains * will not get cached to the same channel. For example, a gRPC example app may use the channel pool diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 85a5a9ac89..cd90bc6893 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -17,6 +17,7 @@ */ #import "GRPCCallOptions.h" +#import "internal/GRPCCallOptions+internal.h" // The default values for the call options. static NSString *const kDefaultServerAuthority = nil; diff --git a/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h b/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h new file mode 100644 index 0000000000..406f268ef2 --- /dev/null +++ b/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +@interface GRPCCallOptions () + +/** + * Parameter used for internal logging. + */ +@property(readonly) id logContext; + +@end + +@interface GRPCMutableCallOptions () + +/** + * Parameter used for internal logging. + */ +@property(readwrite) id logContext; + +@end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 1dfae32342..86f7667851 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -26,6 +26,7 @@ #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "version.h" +#import "../internal/GRPCCallOptions+internal.h" #import #include diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 38b31c2ebc..592e8fe776 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -32,6 +32,7 @@ #import "GRPCSecureChannelFactory.h" #import "NSDictionary+GRPC.h" #import "version.h" +#import "../internal/GRPCCallOptions+internal.h" NS_ASSUME_NONNULL_BEGIN diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template index a3190c2d8e..a3ed1d7858 100644 --- a/templates/gRPC.podspec.template +++ b/templates/gRPC.podspec.template @@ -60,7 +60,7 @@ ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" ss.exclude_files = "#{src_dir}/GRPCCall+GID.{h,m}" - ss.private_header_files = "#{src_dir}/private/*.h" + ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/GRPCCallOptions+Internal.h" ss.dependency 'gRPC-Core', version end -- cgit v1.2.3 From 35f6ab959e7f3d05d35aa7baeeeddeba559969f6 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 13:10:44 -0700 Subject: unsigned int -> NSUInteger --- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 86f7667851..7b800686d0 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -104,9 +104,9 @@ extern const char *kCFStreamVarName; if (_callOptions.keepaliveInterval != 0) { args[@GRPC_ARG_KEEPALIVE_TIME_MS] = - [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.keepaliveInterval * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveInterval * 1000)]; args[@GRPC_ARG_KEEPALIVE_TIMEOUT_MS] = - [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.keepaliveTimeout * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveTimeout * 1000)]; } if (_callOptions.retryEnabled == NO) { @@ -115,15 +115,15 @@ extern const char *kCFStreamVarName; if (_callOptions.connectMinTimeout > 0) { args[@GRPC_ARG_MIN_RECONNECT_BACKOFF_MS] = - [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.connectMinTimeout * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMinTimeout * 1000)]; } if (_callOptions.connectInitialBackoff > 0) { args[@GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS] = [NSNumber - numberWithUnsignedInteger:(unsigned int)(_callOptions.connectInitialBackoff * 1000)]; + numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectInitialBackoff * 1000)]; } if (_callOptions.connectMaxBackoff > 0) { args[@GRPC_ARG_MAX_RECONNECT_BACKOFF_MS] = - [NSNumber numberWithUnsignedInteger:(unsigned int)(_callOptions.connectMaxBackoff * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMaxBackoff * 1000)]; } if (_callOptions.logContext != nil) { -- cgit v1.2.3 From cc58524994eddfbbc7cd800efe1462a7ec28d4f0 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 13:11:06 -0700 Subject: isChannelOptionsEqualTo->hasChannelOptionsEqualTo --- src/objective-c/GRPCClient/GRPCCallOptions.h | 2 +- src/objective-c/GRPCClient/GRPCCallOptions.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 4f02b344b1..9683bd3c63 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -199,7 +199,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { /** * Return if the channel options are equal to another object. */ -- (BOOL)isChannelOptionsEqualTo:(GRPCCallOptions *)callOptions; +- (BOOL)hasChannelOptionsEqualTo:(GRPCCallOptions *)callOptions; /** * Hash for channel options. diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index cd90bc6893..ba3255f0e4 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -229,7 +229,7 @@ static const NSUInteger kDefaultChannelID = 0; return newOptions; } -- (BOOL)isChannelOptionsEqualTo:(GRPCCallOptions *)callOptions { +- (BOOL)hasChannelOptionsEqualTo:(GRPCCallOptions *)callOptions { if (!(callOptions.userAgentPrefix == _userAgentPrefix || [callOptions.userAgentPrefix isEqualToString:_userAgentPrefix])) return NO; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 7b800686d0..61f5a55077 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -150,7 +150,7 @@ extern const char *kCFStreamVarName; NSAssert([object isKindOfClass:[GRPCChannelConfiguration class]], @"Illegal :isEqual"); GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; if (!(obj.host == _host || [obj.host isEqualToString:_host])) return NO; - if (!(obj.callOptions == _callOptions || [obj.callOptions isChannelOptionsEqualTo:_callOptions])) + if (!(obj.callOptions == _callOptions || [obj.callOptions hasChannelOptionsEqualTo:_callOptions])) return NO; return YES; -- cgit v1.2.3 From 26108e1106cffd1767f0b7fb6ff4b0672ed6a640 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 23 Oct 2018 13:14:24 -0700 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.h | 18 ++++++++------- src/objective-c/GRPCClient/GRPCCallOptions.m | 10 ++++----- .../GRPCClient/private/GRPCChannelPool.m | 2 +- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- src/objective-c/ProtoRPC/ProtoRPC.h | 4 ++-- src/objective-c/ProtoRPC/ProtoRPC.m | 26 ++++++++++++---------- 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 85d0a302d1..a1f139fc18 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -156,9 +156,9 @@ extern NSString *const kGRPCTrailersKey; @optional /** - * Issued when initial metadata is received from the server. The task must be scheduled onto the - * dispatch queue in property \a dispatchQueue. - */ + * Issued when initial metadata is received from the server. The task must be scheduled onto the + * dispatch queue in property \a dispatchQueue. + */ - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; /** @@ -309,7 +309,7 @@ NS_ASSUME_NONNULL_END * * The property is initialized to an empty NSMutableDictionary. */ -@property(null_unspecified, atomic, readonly) NSMutableDictionary * requestHeaders; +@property(null_unspecified, atomic, readonly) NSMutableDictionary *requestHeaders; /** * This dictionary is populated with the HTTP headers received from the server. This happens before @@ -342,9 +342,9 @@ NS_ASSUME_NONNULL_END * host parameter should not contain the scheme (http:// or https://), only the name or IP addr * and the port number, for example @"localhost:5050". */ -- (instancetype _Null_unspecified)initWithHost:(NSString * _Null_unspecified)host - path:(NSString * _Null_unspecified)path - requestsWriter:(GRXWriter * _Null_unspecified)requestWriter; +- (instancetype _Null_unspecified)initWithHost:(NSString *_Null_unspecified)host + path:(NSString *_Null_unspecified)path + requestsWriter:(GRXWriter *_Null_unspecified)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and @@ -355,7 +355,9 @@ NS_ASSUME_NONNULL_END /** * The following methods are deprecated. */ -+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString * _Null_unspecified)host path:(NSString * _Null_unspecified)path; ++ (void)setCallSafety:(GRPCCallSafety)callSafety + host:(NSString *_Null_unspecified)host + path:(NSString *_Null_unspecified)path; @property(null_unspecified, atomic, copy, readwrite) NSString *serverName; @property NSTimeInterval timeout; - (void)setResponseDispatchQueue:(dispatch_queue_t _Null_unspecified)queue; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index ba3255f0e4..0977a4ccdb 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -183,7 +183,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - retryEnabled:_retryEnabled + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout @@ -211,7 +211,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - retryEnabled:_retryEnabled + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout @@ -328,7 +328,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:kDefaultUserAgentPrefix responseSizeLimit:kDefaultResponseSizeLimit compressionAlgorithm:kDefaultCompressionAlgorithm - retryEnabled:kDefaultRetryEnabled + retryEnabled:kDefaultRetryEnabled keepaliveInterval:kDefaultKeepaliveInterval keepaliveTimeout:kDefaultKeepaliveTimeout connectMinTimeout:kDefaultConnectMinTimeout @@ -355,7 +355,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - retryEnabled:_retryEnabled + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout @@ -383,7 +383,7 @@ static const NSUInteger kDefaultChannelID = 0; userAgentPrefix:_userAgentPrefix responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm - retryEnabled:_retryEnabled + retryEnabled:_retryEnabled keepaliveInterval:_keepaliveInterval keepaliveTimeout:_keepaliveTimeout connectMinTimeout:_connectMinTimeout diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 61f5a55077..56f76450b2 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -18,6 +18,7 @@ #import +#import "../internal/GRPCCallOptions+internal.h" #import "GRPCChannel.h" #import "GRPCChannelFactory.h" #import "GRPCChannelPool.h" @@ -26,7 +27,6 @@ #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "version.h" -#import "../internal/GRPCCallOptions+internal.h" #import #include diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 592e8fe776..ab5b69cc4e 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -25,6 +25,7 @@ #include #include +#import "../internal/GRPCCallOptions+internal.h" #import "GRPCChannelFactory.h" #import "GRPCCompletionQueue.h" #import "GRPCConnectivityMonitor.h" @@ -32,7 +33,6 @@ #import "GRPCSecureChannelFactory.h" #import "NSDictionary+GRPC.h" #import "version.h" -#import "../internal/GRPCCallOptions+internal.h" NS_ASSUME_NONNULL_BEGIN diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 6f4b9eed75..635ba0c90e 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -31,8 +31,8 @@ NS_ASSUME_NONNULL_BEGIN @optional /** - * Issued when initial metadata is received from the server. The task must be scheduled onto the - * dispatch queue in property \a dispatchQueue. */ + * Issued when initial metadata is received from the server. The task must be scheduled onto the + * dispatch queue in property \a dispatchQueue. */ - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; /** diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 27070a891d..34891e8953 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -28,19 +28,19 @@ #import /** - * Generate an NSError object that represents a failure in parsing a proto class. - */ + * Generate an NSError object that represents a failure in parsing a proto class. + */ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { NSDictionary *info = @{ - NSLocalizedDescriptionKey : @"Unable to parse response from the server", - NSLocalizedRecoverySuggestionErrorKey : - @"If this RPC is idempotent, retry " - @"with exponential backoff. Otherwise, query the server status before " - @"retrying.", - NSUnderlyingErrorKey : parsingError, - @"Expected class" : expectedClass, - @"Received value" : proto, - }; + NSLocalizedDescriptionKey : @"Unable to parse response from the server", + NSLocalizedRecoverySuggestionErrorKey : + @"If this RPC is idempotent, retry " + @"with exponential backoff. Otherwise, query the server status before " + @"retrying.", + NSUnderlyingErrorKey : parsingError, + @"Expected class" : expectedClass, + @"Received value" : proto, + }; // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public. return [NSError errorWithDomain:@"io.grpc" code:13 userInfo:info]; } @@ -190,7 +190,9 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } } else { if ([self->_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [self->_handler closedWithTrailingMetadata:nil error:ErrorForBadProto(message, _responseClass, error)]; + [self->_handler + closedWithTrailingMetadata:nil + error:ErrorForBadProto(message, _responseClass, error)]; } self->_handler = nil; [self->_call cancel]; -- cgit v1.2.3 From 1cbb484729706cf89b140b8a746562a53d916e8b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 24 Oct 2018 10:45:07 -0700 Subject: Fix build failure --- src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h | 2 ++ src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h b/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h index 406f268ef2..eb691b3acb 100644 --- a/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h +++ b/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h @@ -18,6 +18,8 @@ #import +#import "../GRPCCallOptions.h" + @interface GRPCCallOptions () /** diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index 7067578467..f976e1e06a 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -53,14 +53,14 @@ NS_ASSUME_NONNULL_BEGIN } - (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args { + channelArgs:(NSDictionary *)args { // Remove client authority filter since that is not supported args[@GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER] = [NSNumber numberWithInt:1]; - grpc_channel_args *channelArgs = BuildChannelArgs(args); + grpc_channel_args *channelArgs = GRPCBuildChannelArgs(args); grpc_channel *unmanagedChannel = grpc_cronet_secure_channel_create(_cronetEngine, host.UTF8String, channelArgs, NULL); - FreeChannelArgs(channelArgs); + GRPCFreeChannelArgs(channelArgs); return unmanagedChannel; } -- cgit v1.2.3 From 3c33020357e58202a9909d739353f4c20f78e817 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 24 Oct 2018 13:31:45 -0700 Subject: Polish nullabitily --- .../GRPCClient/private/GRPCChannelFactory.h | 4 ++-- .../GRPCClient/private/GRPCCronetChannelFactory.h | 8 ++++---- .../GRPCClient/private/GRPCCronetChannelFactory.m | 14 +++++++------- .../GRPCClient/private/GRPCInsecureChannelFactory.h | 8 ++++---- .../GRPCClient/private/GRPCInsecureChannelFactory.m | 6 +++--- .../GRPCClient/private/GRPCSecureChannelFactory.h | 12 ++++++------ .../GRPCClient/private/GRPCSecureChannelFactory.m | 18 +++++++++--------- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h index a934e966e9..287233f246 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h @@ -26,8 +26,8 @@ NS_ASSUME_NONNULL_BEGIN @protocol GRPCChannelFactory /** Create a channel with specific channel args to a specific host. */ -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args; +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args; @end diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h index 738dfdb737..18e84b81fa 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h @@ -24,12 +24,12 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCCronetChannelFactory : NSObject -+ (nullable instancetype)sharedInstance; ++ (instancetype _Nullable)sharedInstance; -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args; +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args; -- (nullable instancetype)init NS_UNAVAILABLE; +- (instancetype _Nullable)init NS_UNAVAILABLE; @end diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index f976e1e06a..b2ab03b648 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN stream_engine *_cronetEngine; } -+ (nullable instancetype)sharedInstance { ++ (instancetype _Nullable)sharedInstance { static GRPCCronetChannelFactory *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -41,7 +41,7 @@ NS_ASSUME_NONNULL_BEGIN return instance; } -- (nullable instancetype)initWithEngine:(stream_engine *)engine { +- (instancetype _Nullable)initWithEngine:(stream_engine *)engine { if (!engine) { [NSException raise:NSInvalidArgumentException format:@"Cronet engine is NULL. Set it first."]; return nil; @@ -52,8 +52,8 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *)args { +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args { // Remove client authority filter since that is not supported args[@GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER] = [NSNumber numberWithInt:1]; @@ -74,14 +74,14 @@ NS_ASSUME_NONNULL_BEGIN @implementation GRPCCronetChannelFactory -+ (nullable instancetype)sharedInstance { ++ (instancetype _Nullable)sharedInstance { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; return nil; } -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args { +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; return NULL; diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h index 2d471aebed..1175483c68 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h @@ -23,12 +23,12 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCInsecureChannelFactory : NSObject -+ (nullable instancetype)sharedInstance; ++ (instancetype _Nullable)sharedInstance; -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args; +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args; -- (nullable instancetype)init NS_UNAVAILABLE; +- (instancetype _Nullable)init NS_UNAVAILABLE; @end diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m index 5773f2d9af..44e94831e9 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN @implementation GRPCInsecureChannelFactory -+ (nullable instancetype)sharedInstance { ++ (instancetype _Nullable)sharedInstance { static GRPCInsecureChannelFactory *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -34,8 +34,8 @@ NS_ASSUME_NONNULL_BEGIN return instance; } -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args { +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h index 588239b706..565f58a4fa 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h @@ -23,15 +23,15 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCSecureChannelFactory : NSObject -+ (nullable instancetype)factoryWithPEMRootCertificates:(nullable NSString *)rootCerts - privateKey:(nullable NSString *)privateKey - certChain:(nullable NSString *)certChain ++ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString * _Nullable)rootCerts + privateKey:(NSString * _Nullable)privateKey + certChain:(NSString * _Nullable)certChain error:(NSError **)errorPtr; -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args; +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args; -- (nullable instancetype)init NS_UNAVAILABLE; +- (instancetype _Nullable)init NS_UNAVAILABLE; @end diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index aa8b52e6b8..03cfff2ed4 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -29,9 +29,9 @@ NS_ASSUME_NONNULL_BEGIN grpc_channel_credentials *_channelCreds; } -+ (nullable instancetype)factoryWithPEMRootCertificates:(nullable NSString *)rootCerts - privateKey:(nullable NSString *)privateKey - certChain:(nullable NSString *)certChain ++ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString * _Nullable)rootCerts + privateKey:(NSString * _Nullable)privateKey + certChain:(NSString * _Nullable)certChain error:(NSError **)errorPtr { return [[self alloc] initWithPEMRootCerts:rootCerts privateKey:privateKey @@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN error:errorPtr]; } -- (NSData *)nullTerminatedDataWithString:(NSString *)string { +- (NSData * _Nullable)nullTerminatedDataWithString:(NSString * _Nullable)string { // dataUsingEncoding: does not return a null-terminated string. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; if (data == nil) { @@ -50,9 +50,9 @@ NS_ASSUME_NONNULL_BEGIN return nullTerminated; } -- (nullable instancetype)initWithPEMRootCerts:(nullable NSString *)rootCerts - privateKey:(nullable NSString *)privateKey - certChain:(nullable NSString *)certChain +- (instancetype _Nullable)initWithPEMRootCerts:(NSString * _Nullable)rootCerts + privateKey:(NSString * _Nullable)privateKey + certChain:(NSString * _Nullable)certChain error:(NSError **)errorPtr { static NSData *defaultRootsASCII; static NSError *defaultRootsError; @@ -116,8 +116,8 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (nullable grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(nullable NSDictionary *)args { +- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary * _Nullable)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); -- cgit v1.2.3 From c2bb7550377898e6985662d0ca9048c07bde6810 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 24 Oct 2018 16:55:23 -0700 Subject: Move GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER into core --- .../cronet/client/secure/cronet_channel_create.cc | 14 ++++++++++++-- .../GRPCClient/private/GRPCCronetChannelFactory.m | 3 --- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 4 +++- .../tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm | 6 ------ src/objective-c/tests/CronetUnitTests/CronetUnitTests.m | 13 +------------ 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc index 40a30e4a31..dffb61b082 100644 --- a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc +++ b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc @@ -46,9 +46,19 @@ GRPCAPI grpc_channel* grpc_cronet_secure_channel_create( "grpc_create_cronet_transport: stream_engine = %p, target=%s", engine, target); + // Disable client authority filter when using Cronet + grpc_arg arg; + arg.key = const_cast(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); + arg.type = GRPC_ARG_INTEGER; + arg.value.integer = 1; + grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args, &arg, 1); + grpc_transport* ct = - grpc_create_cronet_transport(engine, target, args, reserved); + grpc_create_cronet_transport(engine, target, new_args, reserved); grpc_core::ExecCtx exec_ctx; - return grpc_channel_create(target, args, GRPC_CLIENT_DIRECT_CHANNEL, ct); + grpc_channel* channel = + grpc_channel_create(target, new_args, GRPC_CLIENT_DIRECT_CHANNEL, ct); + grpc_channel_args_destroy(new_args); + return channel; } diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index b2ab03b648..51d8df0fb7 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -54,9 +54,6 @@ NS_ASSUME_NONNULL_BEGIN - (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary * _Nullable)args { - // Remove client authority filter since that is not supported - args[@GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER] = [NSNumber numberWithInt:1]; - grpc_channel_args *channelArgs = GRPCBuildChannelArgs(args); grpc_channel *unmanagedChannel = grpc_cronet_secure_channel_create(_cronetEngine, host.UTF8String, channelArgs, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 4d5257aca7..100d4cf291 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -310,7 +310,9 @@ } - (void)dealloc { - grpc_call_unref(_call); + if (_call) { + grpc_call_unref(_call); + } [_channel unref]; _channel = nil; } diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm index 80fa0f4785..fe85e915d4 100644 --- a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm +++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm @@ -81,13 +81,7 @@ static void cronet_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, stream_engine *cronetEngine) { fullstack_secure_fixture_data *ffd = (fullstack_secure_fixture_data *)f->fixture_data; - grpc_arg arg; - arg.key = const_cast(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); - arg.type = GRPC_ARG_INTEGER; - arg.value.integer = 1; - client_args = grpc_channel_args_copy_and_add(client_args, &arg, 1); f->client = grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr, client_args, NULL); - grpc_channel_args_destroy(client_args); GPR_ASSERT(f->client != NULL); } diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m index 84893b92c1..d732bc6ba9 100644 --- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m +++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m @@ -124,14 +124,6 @@ unsigned int parse_h2_length(const char *field) { ((unsigned int)(unsigned char)(field[2])); } -grpc_channel_args *add_disable_client_authority_filter_args(grpc_channel_args *args) { - grpc_arg arg; - arg.key = const_cast(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); - arg.type = GRPC_ARG_INTEGER; - arg.value.integer = 1; - return grpc_channel_args_copy_and_add(args, &arg, 1); -} - - (void)testInternalError { grpc_call *c; grpc_slice request_payload_slice = grpc_slice_from_copied_string("hello world"); @@ -151,9 +143,7 @@ grpc_channel_args *add_disable_client_authority_filter_args(grpc_channel_args *a gpr_join_host_port(&addr, "127.0.0.1", port); grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); stream_engine *cronetEngine = [Cronet getGlobalEngine]; - grpc_channel_args *client_args = add_disable_client_authority_filter_args(NULL); - grpc_channel *client = grpc_cronet_secure_channel_create(cronetEngine, addr, client_args, NULL); - grpc_channel_args_destroy(client_args); + grpc_channel *client = grpc_cronet_secure_channel_create(cronetEngine, addr, NULL, NULL); cq_verifier *cqv = cq_verifier_create(cq); grpc_op ops[6]; @@ -265,7 +255,6 @@ grpc_channel_args *add_disable_client_authority_filter_args(grpc_channel_args *a arg.type = GRPC_ARG_INTEGER; arg.value.integer = useCoalescing ? 1 : 0; grpc_channel_args *args = grpc_channel_args_copy_and_add(NULL, &arg, 1); - args = add_disable_client_authority_filter_args(args); grpc_call *c; grpc_slice request_payload_slice = grpc_slice_from_copied_string("hello world"); -- cgit v1.2.3 From a8a7c2bdd10eb7dc9e072327da2ddb70e5785cf7 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 24 Oct 2018 17:05:38 -0700 Subject: clang-format --- .../GRPCClient/private/GRPCChannelFactory.h | 4 ++-- .../GRPCClient/private/GRPCCronetChannelFactory.h | 4 ++-- .../GRPCClient/private/GRPCCronetChannelFactory.m | 8 ++++---- .../private/GRPCInsecureChannelFactory.h | 4 ++-- .../private/GRPCInsecureChannelFactory.m | 4 ++-- .../GRPCClient/private/GRPCSecureChannelFactory.h | 12 ++++++------ .../GRPCClient/private/GRPCSecureChannelFactory.m | 22 +++++++++++----------- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h index 287233f246..3a3500fc95 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h @@ -26,8 +26,8 @@ NS_ASSUME_NONNULL_BEGIN @protocol GRPCChannelFactory /** Create a channel with specific channel args to a specific host. */ -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args; +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args; @end diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h index 18e84b81fa..5e35576ea1 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h @@ -26,8 +26,8 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype _Nullable)sharedInstance; -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args; +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args; - (instancetype _Nullable)init NS_UNAVAILABLE; diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index 51d8df0fb7..781881d211 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -52,8 +52,8 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args { +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args { grpc_channel_args *channelArgs = GRPCBuildChannelArgs(args); grpc_channel *unmanagedChannel = grpc_cronet_secure_channel_create(_cronetEngine, host.UTF8String, channelArgs, NULL); @@ -77,8 +77,8 @@ NS_ASSUME_NONNULL_BEGIN return nil; } -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args { +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; return NULL; diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h index 1175483c68..98a985fe84 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h @@ -25,8 +25,8 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype _Nullable)sharedInstance; -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args; +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args; - (instancetype _Nullable)init NS_UNAVAILABLE; diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m index 44e94831e9..9969887712 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -34,8 +34,8 @@ NS_ASSUME_NONNULL_BEGIN return instance; } -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args { +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h index 565f58a4fa..02e7052996 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h @@ -23,13 +23,13 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCSecureChannelFactory : NSObject -+ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString * _Nullable)rootCerts - privateKey:(NSString * _Nullable)privateKey - certChain:(NSString * _Nullable)certChain - error:(NSError **)errorPtr; ++ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString *_Nullable)rootCerts + privateKey:(NSString *_Nullable)privateKey + certChain:(NSString *_Nullable)certChain + error:(NSError **)errorPtr; -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args; +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args; - (instancetype _Nullable)init NS_UNAVAILABLE; diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 03cfff2ed4..1f6458c524 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -29,17 +29,17 @@ NS_ASSUME_NONNULL_BEGIN grpc_channel_credentials *_channelCreds; } -+ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString * _Nullable)rootCerts - privateKey:(NSString * _Nullable)privateKey - certChain:(NSString * _Nullable)certChain - error:(NSError **)errorPtr { ++ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString *_Nullable)rootCerts + privateKey:(NSString *_Nullable)privateKey + certChain:(NSString *_Nullable)certChain + error:(NSError **)errorPtr { return [[self alloc] initWithPEMRootCerts:rootCerts privateKey:privateKey certChain:certChain error:errorPtr]; } -- (NSData * _Nullable)nullTerminatedDataWithString:(NSString * _Nullable)string { +- (NSData *_Nullable)nullTerminatedDataWithString:(NSString *_Nullable)string { // dataUsingEncoding: does not return a null-terminated string. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; if (data == nil) { @@ -50,10 +50,10 @@ NS_ASSUME_NONNULL_BEGIN return nullTerminated; } -- (instancetype _Nullable)initWithPEMRootCerts:(NSString * _Nullable)rootCerts - privateKey:(NSString * _Nullable)privateKey - certChain:(NSString * _Nullable)certChain - error:(NSError **)errorPtr { +- (instancetype _Nullable)initWithPEMRootCerts:(NSString *_Nullable)rootCerts + privateKey:(NSString *_Nullable)privateKey + certChain:(NSString *_Nullable)certChain + error:(NSError **)errorPtr { static NSData *defaultRootsASCII; static NSError *defaultRootsError; static dispatch_once_t loading; @@ -116,8 +116,8 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (grpc_channel * _Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary * _Nullable)args { +- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *_Nullable)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); -- cgit v1.2.3 From f9d2510d8f655badea3dea14493b6d4d3882705a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 26 Oct 2018 11:15:16 -0700 Subject: Specify nullability in ProtoRPC --- src/objective-c/ProtoRPC/ProtoRPC.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 635ba0c90e..b0f4ced99e 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -134,10 +134,11 @@ __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC * addr and the port number, for example @"localhost:5050". */ - - (instancetype)initWithHost : (NSString *)host method - : (GRPCProtoMethod *)method requestsWriter : (GRXWriter *)requestsWriter responseClass - : (Class)responseClass responsesWriteable - : (id)responsesWriteable NS_DESIGNATED_INITIALIZER; + (instancetype _Null_unspecified)initWithHost : (NSString *_Null_unspecified)host method + : (GRPCProtoMethod *_Null_unspecified)method requestsWriter + : (GRXWriter *_Null_unspecified)requestsWriter responseClass + : (Class _Null_unspecified)responseClass responsesWriteable + : (id _Null_unspecified)responsesWriteable NS_DESIGNATED_INITIALIZER; - (void)start; @end -- cgit v1.2.3 From a8c4eb7d2742eb3ba370d9801cc1b83e35d551a9 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 29 Oct 2018 14:15:26 -0700 Subject: Bug fix --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 85a2837336..44432a120a 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -782,7 +782,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; _callOptions = callOptions; } - NSAssert(_callOptions.authTokenProvider != nil || _callOptions.oauth2AccessToken != nil, + NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); if (_callOptions.authTokenProvider != nil) { @synchronized(self) { -- cgit v1.2.3 From abe4aae40049ca73fb29ccf325cc3734408d9aae Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 29 Oct 2018 15:21:05 -0700 Subject: Remove length check in GRPCCall for backwards compatibility --- src/objective-c/GRPCClient/GRPCCall.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 44432a120a..ca2cdd6b31 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -391,7 +391,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; callSafety:(GRPCCallSafety)safety requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { - if (host.length == 0 || path.length == 0) { + // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. + if (!host || !path) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil or empty."]; } -- cgit v1.2.3 From aec84416a4308e547736569f2bc815a8bbd9c80f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 29 Oct 2018 15:48:16 -0700 Subject: Remove NS_UNAVAILABLE for backwards compatibility --- src/objective-c/ProtoRPC/ProtoService.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index 3a16ab2402..2105de78a3 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -31,14 +31,9 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoServ : NSObject - - (instancetype)init NS_UNAVAILABLE; - -+ (instancetype) new NS_UNAVAILABLE; - -- (instancetype)initWithHost:(NSString *)host - packageName:(NSString *)packageName - serviceName:(NSString *)serviceName - callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; + (instancetype)initWithHost : (NSString *)host packageName + : (NSString *)packageName serviceName : (NSString *)serviceName callOptions + : (GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; - (instancetype)initWithHost:(NSString *)host packageName:(NSString *)packageName -- cgit v1.2.3 From 0cabf27fa3e5afc4918a6aaf7d51825d7c0eb8e0 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 31 Oct 2018 18:25:49 -0700 Subject: Clean codes --- src/objective-c/GRPCClient/GRPCCall.m | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index ca2cdd6b31..505d84a954 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -167,13 +167,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; id responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(id value) { dispatch_async(self->_dispatchQueue, ^{ if (self->_handler) { - NSDictionary *headers = nil; if (!self->_initialMetadataPublished) { - headers = self->_call.responseHeaders; self->_initialMetadataPublished = YES; - } - if (headers) { - [self issueInitialMetadata:headers]; + [self issueInitialMetadata:self->_call.responseHeaders]; } if (value) { [self issueMessage:value]; @@ -184,13 +180,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; completionHandler:^(NSError *errorOrNil) { dispatch_async(self->_dispatchQueue, ^{ if (self->_handler) { - NSDictionary *headers = nil; if (!self->_initialMetadataPublished) { - headers = self->_call.responseHeaders; self->_initialMetadataPublished = YES; - } - if (headers) { - [self issueInitialMetadata:headers]; + [self issueInitialMetadata:self->_call.responseHeaders]; } [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; -- cgit v1.2.3 From a37ec5e3e6f7184458108bd5419ce6b832061975 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 31 Oct 2018 18:26:02 -0700 Subject: Polish error message --- src/objective-c/GRPCClient/GRPCCall.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 505d84a954..5aeedba9a7 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -385,8 +385,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; callOptions:(GRPCCallOptions *)callOptions { // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. if (!host || !path) { - [NSException raise:NSInvalidArgumentException - format:@"Neither host nor path can be nil or empty."]; + [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; } if (safety > GRPCCallSafetyCacheableRequest) { [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; -- cgit v1.2.3 From 16fd5a758c2418dcf0be3a0985e68b1e15582387 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 31 Oct 2018 18:26:39 -0700 Subject: Remove __block for synchronized blocks --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 5aeedba9a7..8e7d5a5f94 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -564,7 +564,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } NSMutableDictionary *headers = _requestHeaders; - __block NSString *fetchedOauth2AccessToken; + NSString *fetchedOauth2AccessToken; @synchronized(self) { fetchedOauth2AccessToken = _fetchedOauth2AccessToken; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 56f76450b2..7aac077e77 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -190,7 +190,7 @@ extern const char *kCFStreamVarName; } - (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration { - __block GRPCChannel *channel; + GRPCChannel *channel; @synchronized(self) { if ([_channelPool objectForKey:configuration]) { channel = _channelPool[configuration]; diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index ab5b69cc4e..480e462184 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -141,7 +141,7 @@ static NSMutableDictionary *gHostCache; host = [hostURL.host stringByAppendingString:@":443"]; } - __block GRPCCallOptions *callOptions = nil; + GRPCCallOptions *callOptions = nil; @synchronized(gHostCache) { if ([gHostCache objectForKey:host]) { callOptions = [gHostCache[host] callOptions]; -- cgit v1.2.3 From 73251477bc4f7cb10bf40c9f56df8a65d58689f1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 09:03:23 -0700 Subject: clamp positive NSTimeInterval in initializer --- src/objective-c/GRPCClient/GRPCCallOptions.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 0977a4ccdb..8bb2ad29fc 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -146,7 +146,7 @@ static const NSUInteger kDefaultChannelID = 0; channelID:(NSUInteger)channelID { if ((self = [super init])) { _serverAuthority = [serverAuthority copy]; - _timeout = timeout; + _timeout = timeout < 0 ? 0 : timeout; _oauth2AccessToken = [oauth2AccessToken copy]; _authTokenProvider = authTokenProvider; _initialMetadata = [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES]; @@ -154,11 +154,11 @@ static const NSUInteger kDefaultChannelID = 0; _responseSizeLimit = responseSizeLimit; _compressionAlgorithm = compressionAlgorithm; _retryEnabled = retryEnabled; - _keepaliveInterval = keepaliveInterval; - _keepaliveTimeout = keepaliveTimeout; - _connectMinTimeout = connectMinTimeout; - _connectInitialBackoff = connectInitialBackoff; - _connectMaxBackoff = connectMaxBackoff; + _keepaliveInterval = keepaliveInterval < 0 ? 0 : keepaliveInterval; + _keepaliveTimeout = keepaliveTimeout < 0 ? 0 : keepaliveTimeout; + _connectMinTimeout = connectMinTimeout < 0 ? 0 : connectMinTimeout; + _connectInitialBackoff = connectInitialBackoff < 0 ? 0 : connectInitialBackoff; + _connectMaxBackoff = connectMaxBackoff < 0 ? 0 : connectMaxBackoff; _additionalChannelArgs = [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; _PEMRootCertificates = [PEMRootCertificates copy]; -- cgit v1.2.3 From 790adca8e397d78affef7589e1ddf94b80b052f1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 09:18:50 -0700 Subject: copy items in GRPCCallOptions:mutableCopy: --- src/objective-c/GRPCClient/GRPCCallOptions.m | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 8bb2ad29fc..c7096cf1cf 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -203,12 +203,13 @@ static const NSUInteger kDefaultChannelID = 0; - (nonnull id)mutableCopyWithZone:(NSZone *)zone { GRPCMutableCallOptions *newOptions = [[GRPCMutableCallOptions allocWithZone:zone] - initWithServerAuthority:_serverAuthority + initWithServerAuthority:[_serverAuthority copy] timeout:_timeout - oauth2AccessToken:_oauth2AccessToken + oauth2AccessToken:[_oauth2AccessToken copy] authTokenProvider:_authTokenProvider - initialMetadata:_initialMetadata - userAgentPrefix:_userAgentPrefix + initialMetadata:[[NSDictionary alloc] initWithDictionary:_initialMetadata + copyItems:YES] + userAgentPrefix:[_userAgentPrefix copy] responseSizeLimit:_responseSizeLimit compressionAlgorithm:_compressionAlgorithm retryEnabled:_retryEnabled @@ -217,14 +218,15 @@ static const NSUInteger kDefaultChannelID = 0; connectMinTimeout:_connectMinTimeout connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff - additionalChannelArgs:[_additionalChannelArgs copy] - PEMRootCertificates:_PEMRootCertificates - PEMPrivateKey:_PEMPrivateKey - PEMCertChain:_PEMCertChain + additionalChannelArgs:[[NSDictionary alloc] initWithDictionary:_additionalChannelArgs + copyItems:YES] + PEMRootCertificates:[_PEMRootCertificates copy] + PEMPrivateKey:[_PEMPrivateKey copy] + PEMCertChain:[_PEMCertChain copy] transportType:_transportType - hostNameOverride:_hostNameOverride + hostNameOverride:[_hostNameOverride copy] logContext:_logContext - channelPoolDomain:_channelPoolDomain + channelPoolDomain:[_channelPoolDomain copy] channelID:_channelID]; return newOptions; } -- cgit v1.2.3 From ce53ba74746248ef914986bc5fe8a2f89f42ceda Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 09:27:40 -0700 Subject: kChannelDestroyDelay->_destroyDelay in GRPCChannelRef --- src/objective-c/GRPCClient/private/GRPCChannel.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 777cbab809..67a3ac1274 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -109,7 +109,7 @@ static GRPCChannelPool *gChannelPool; if (self->_refCount == 0) { self->_lastDispatch = [NSDate date]; dispatch_time_t delay = - dispatch_time(DISPATCH_TIME_NOW, (int64_t)kChannelDestroyDelay * 1e9); + dispatch_time(DISPATCH_TIME_NOW, (int64_t)_destroyDelay * 1e9); dispatch_after(delay, self->_timerQueue, ^{ [self timerFire]; }); @@ -132,7 +132,7 @@ static GRPCChannelPool *gChannelPool; - (void)timerFire { dispatch_async(_dispatchQueue, ^{ if (self->_disconnected || self->_lastDispatch == nil || - -[self->_lastDispatch timeIntervalSinceNow] < -kChannelDestroyDelay) { + -[self->_lastDispatch timeIntervalSinceNow] < -_destroyDelay) { return; } self->_lastDispatch = nil; -- cgit v1.2.3 From dc4fc1ce38f9060c10ae639173d106c5a7d2bece Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 09:29:15 -0700 Subject: Use NSEC_PER_SEC --- src/objective-c/GRPCClient/private/GRPCChannel.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 67a3ac1274..377900fd9e 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -109,7 +109,7 @@ static GRPCChannelPool *gChannelPool; if (self->_refCount == 0) { self->_lastDispatch = [NSDate date]; dispatch_time_t delay = - dispatch_time(DISPATCH_TIME_NOW, (int64_t)_destroyDelay * 1e9); + dispatch_time(DISPATCH_TIME_NOW, (int64_t)self->_destroyDelay * NSEC_PER_SEC); dispatch_after(delay, self->_timerQueue, ^{ [self timerFire]; }); @@ -132,7 +132,7 @@ static GRPCChannelPool *gChannelPool; - (void)timerFire { dispatch_async(_dispatchQueue, ^{ if (self->_disconnected || self->_lastDispatch == nil || - -[self->_lastDispatch timeIntervalSinceNow] < -_destroyDelay) { + -[self->_lastDispatch timeIntervalSinceNow] < -self->_destroyDelay) { return; } self->_lastDispatch = nil; -- cgit v1.2.3 From 601475b57105f0aff3e96043e6399b621cfc5b84 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 11:43:09 -0700 Subject: Easier check if timer is canceled --- src/objective-c/GRPCClient/private/GRPCChannel.m | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 377900fd9e..1d7fb421e5 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -66,6 +66,12 @@ static GRPCChannelPool *gChannelPool; BOOL _disconnected; dispatch_queue_t _dispatchQueue; dispatch_queue_t _timerQueue; + + /** + * Date and time when last timer is scheduled. When a timer is fired, if + * _lastDispatch + _destroyDelay < now, it can be determined that another timer is scheduled after + * schedule of the current timer, hence the current one should be discarded. + */ NSDate *_lastDispatch; } @@ -107,11 +113,12 @@ static GRPCChannelPool *gChannelPool; if (!self->_disconnected) { self->_refCount--; if (self->_refCount == 0) { - self->_lastDispatch = [NSDate date]; + NSDate *now = [NSDate date]; + self->_lastDispatch = now; dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)self->_destroyDelay * NSEC_PER_SEC); dispatch_after(delay, self->_timerQueue, ^{ - [self timerFire]; + [self timerFireWithScheduleDate:now]; }); } } @@ -129,10 +136,9 @@ static GRPCChannelPool *gChannelPool; }); } -- (void)timerFire { +- (void)timerFireWithScheduleDate:(NSDate *)scheduleDate { dispatch_async(_dispatchQueue, ^{ - if (self->_disconnected || self->_lastDispatch == nil || - -[self->_lastDispatch timeIntervalSinceNow] < -self->_destroyDelay) { + if (self->_disconnected || self->_lastDispatch != scheduleDate) { return; } self->_lastDispatch = nil; -- cgit v1.2.3 From 29bf3864d1a3d00b2199adb0d56298c3a32178fb Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 12:44:48 -0700 Subject: Remove object after finish iterating in loop --- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 7aac077e77..56de8a0d6f 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -147,7 +147,9 @@ extern const char *kCFStreamVarName; } - (BOOL)isEqual:(id)object { - NSAssert([object isKindOfClass:[GRPCChannelConfiguration class]], @"Illegal :isEqual"); + if (![object isKindOfClass:[GRPCChannelConfiguration class]]) { + return NO; + } GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; if (!(obj.host == _host || [obj.host isEqualToString:_host])) return NO; if (!(obj.callOptions == _callOptions || [obj.callOptions hasChannelOptionsEqualTo:_callOptions])) @@ -207,13 +209,16 @@ extern const char *kCFStreamVarName; - (void)removeChannel:(GRPCChannel *)channel { @synchronized(self) { + __block GRPCChannelConfiguration *keyToDelete = nil; [_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration *_Nonnull key, GRPCChannel *_Nonnull obj, BOOL *_Nonnull stop) { if (obj == channel) { - [self->_channelPool removeObjectForKey:key]; + keyToDelete = key; + *stop = YES; } }]; + [self->_channelPool removeObjectForKey:keyToDelete]; } } -- cgit v1.2.3 From 395fc1226f1225b267f912f4a860ad52ef6f4e0a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 12:54:38 -0700 Subject: Cleaner code using nil messaging --- src/objective-c/GRPCClient/private/GRPCHost.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 480e462184..8a59bd43d7 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -143,9 +143,7 @@ static NSMutableDictionary *gHostCache; GRPCCallOptions *callOptions = nil; @synchronized(gHostCache) { - if ([gHostCache objectForKey:host]) { - callOptions = [gHostCache[host] callOptions]; - } + callOptions = [gHostCache[host] callOptions]; } if (callOptions == nil) { callOptions = [[GRPCCallOptions alloc] init]; -- cgit v1.2.3 From c827fbc1d044f31a1f925e52e07c843f88094a74 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 13:06:31 -0700 Subject: Log failures when unable to create call or channel --- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 100d4cf291..577002e7a8 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -257,8 +257,13 @@ // queue. Currently we use a singleton queue. _queue = [GRPCCompletionQueue completionQueue]; _channel = [GRPCChannel channelWithHost:host callOptions:callOptions]; + if (_channel == nil) { + NSLog(@"Failed to get a channel for the host."); + return nil; + } _call = [_channel unmanagedCallWithPath:path completionQueue:_queue callOptions:callOptions]; if (_call == NULL) { + NSLog(@"Failed to create a call."); return nil; } } -- cgit v1.2.3 From bc0ce06951b091e81e8bc1c71dc660dc3168e75f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 1 Nov 2018 15:05:58 -0700 Subject: use _dispatchQueue for timer --- src/objective-c/GRPCClient/private/GRPCChannel.m | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 1d7fb421e5..0ca2a35992 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -65,7 +65,6 @@ static GRPCChannelPool *gChannelPool; NSUInteger _refCount; BOOL _disconnected; dispatch_queue_t _dispatchQueue; - dispatch_queue_t _timerQueue; /** * Date and time when last timer is scheduled. When a timer is fired, if @@ -87,12 +86,8 @@ static GRPCChannelPool *gChannelPool; _dispatchQueue = dispatch_queue_create( NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); - _timerQueue = - dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class( - DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_DEFAULT, -1)); } else { _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - _timerQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); } _lastDispatch = nil; } @@ -117,7 +112,7 @@ static GRPCChannelPool *gChannelPool; self->_lastDispatch = now; dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)self->_destroyDelay * NSEC_PER_SEC); - dispatch_after(delay, self->_timerQueue, ^{ + dispatch_after(delay, self->_dispatchQueue, ^{ [self timerFireWithScheduleDate:now]; }); } -- cgit v1.2.3 From 17a67fdb0fb01fe34c75d2c6bf34e24214222a89 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 2 Nov 2018 14:48:56 -0700 Subject: Aggregate v2 api tests --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/GRPCClient/GRPCCallOptions.h | 2 +- src/objective-c/tests/APIv2Tests/APIv2Tests.m | 482 +++++++++++++++++++++ src/objective-c/tests/APIv2Tests/Info.plist | 22 + src/objective-c/tests/GRPCClientTests.m | 291 ------------- src/objective-c/tests/Podfile | 1 + .../tests/Tests.xcodeproj/project.pbxproj | 263 +++++++++++ .../xcshareddata/xcschemes/APIv2Tests.xcscheme | 90 ++++ src/objective-c/tests/run_tests.sh | 10 + 9 files changed, 870 insertions(+), 293 deletions(-) create mode 100644 src/objective-c/tests/APIv2Tests/APIv2Tests.m create mode 100644 src/objective-c/tests/APIv2Tests/Info.plist create mode 100644 src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 8e7d5a5f94..2abc0fe8f3 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -780,7 +780,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; @synchronized(self) { self.isWaitingForToken = YES; } - [self.tokenProvider getTokenWithHandler:^(NSString *token) { + [_callOptions.authTokenProvider getTokenWithHandler:^(NSString *token) { @synchronized(self) { if (self.isWaitingForToken) { if (token) { diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 9683bd3c63..77fde371bc 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -64,7 +64,7 @@ typedef NS_ENUM(NSInteger, GRPCTransportType) { * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ -- (void)getTokenWithHandler:(void (^)(NSString *token))hander; +- (void)getTokenWithHandler:(void (^)(NSString *token))handler; @end @interface GRPCCallOptions : NSObject diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m new file mode 100644 index 0000000000..7fc353391f --- /dev/null +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -0,0 +1,482 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import +#import +#import + +#include + +#import "../version.h" + +// The server address is derived from preprocessor macro, which is +// in turn derived from environment variable of the same name. +#define NSStringize_helper(x) #x +#define NSStringize(x) @NSStringize_helper(x) +static NSString *const kHostAddress = NSStringize(HOST_PORT_LOCAL); +static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE); + +// Package and service name of test server +static NSString *const kPackage = @"grpc.testing"; +static NSString *const kService = @"TestService"; + +static GRPCProtoMethod *kInexistentMethod; +static GRPCProtoMethod *kEmptyCallMethod; +static GRPCProtoMethod *kUnaryCallMethod; +static GRPCProtoMethod *kFullDuplexCallMethod; + +static const int kSimpleDataLength = 100; + +static const NSTimeInterval kTestTimeout = 16; + +// Reveal the _class ivar for testing access +@interface GRPCCall2 () { + @public + GRPCCall *_call; +} + +@end + +// Convenience class to use blocks as callbacks +@interface ClientTestsBlockCallbacks : NSObject + +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback; + +@end + +@implementation ClientTestsBlockCallbacks { + void (^_initialMetadataCallback)(NSDictionary *); + void (^_messageCallback)(id); + void (^_closeCallback)(NSDictionary *, NSError *); + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback + messageCallback:(void (^)(id))messageCallback + closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback { + if ((self = [super init])) { + _initialMetadataCallback = initialMetadataCallback; + _messageCallback = messageCallback; + _closeCallback = closeCallback; + _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { + dispatch_async(_dispatchQueue, ^{ + if (self->_initialMetadataCallback) { + self->_initialMetadataCallback(initialMetadata); + } + }); +} + +- (void)receivedRawMessage:(GPBMessage *_Nullable)message { + dispatch_async(_dispatchQueue, ^{ + if (self->_messageCallback) { + self->_messageCallback(message); + } + }); +} + +- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata + error:(NSError *_Nullable)error { + dispatch_async(_dispatchQueue, ^{ + if (self->_closeCallback) { + self->_closeCallback(trailingMetadata, error); + } + }); +} + +- (dispatch_queue_t)dispatchQueue { + return _dispatchQueue; +} + +@end + +@interface CallAPIv2Tests : XCTestCase + +@end + +@implementation CallAPIv2Tests + +- (void)setUp { + // This method isn't implemented by the remote server. + kInexistentMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"Inexistent"]; + kEmptyCallMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"EmptyCall"]; + kUnaryCallMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"UnaryCall"]; + kFullDuplexCallMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"FullDuplexCall"]; +} + +- (void)testMetadata { + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.fillUsername = YES; + request.fillOauthScope = YES; + + GRPCRequestOptions *callRequest = + [[GRPCRequestOptions alloc] initWithHost:(NSString *)kRemoteSSLHost + path:kUnaryCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + __block NSDictionary *init_md; + __block NSDictionary *trailing_md; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.oauth2AccessToken = @"bogusToken"; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:callRequest + responseHandler:[[ClientTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) { + init_md = initialMetadata; + } + messageCallback:^(id message) { + XCTFail(@"Received unexpected response."); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + trailing_md = trailingMetadata; + if (error) { + XCTAssertEqual(error.code, 16, + @"Finished with unexpected error: %@", error); + XCTAssertEqualObjects(init_md, + error.userInfo[kGRPCHeadersKey]); + XCTAssertEqualObjects(trailing_md, + error.userInfo[kGRPCTrailersKey]); + NSString *challengeHeader = init_md[@"www-authenticate"]; + XCTAssertGreaterThan(challengeHeader.length, 0, + @"No challenge in response headers %@", + init_md); + [expectation fulfill]; + } + }] + callOptions:options]; + + [call start]; + [call writeData:[request data]]; + [call finish]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +- (void)testUserAgentPrefix { + __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; + __weak XCTestExpectation *recvInitialMd = + [self expectationWithDescription:@"Did not receive initial md."]; + + GRPCRequestOptions *request = [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kEmptyCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + NSDictionary *headers = + [NSDictionary dictionaryWithObjectsAndKeys:@"", @"x-grpc-test-echo-useragent", nil]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = GRPCTransportTypeInsecure; + options.userAgentPrefix = @"Foo"; + options.initialMetadata = headers; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:request + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^( + NSDictionary *initialMetadata) { + NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"]; + // Test the regex is correct + NSString *expectedUserAgent = @"Foo grpc-objc/"; + expectedUserAgent = + [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"]; + expectedUserAgent = + [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "]; + expectedUserAgent = [expectedUserAgent + stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"]; + XCTAssertEqualObjects(userAgent, expectedUserAgent); + + NSError *error = nil; + // Change in format of user-agent field in a direction that does not match + // the regex will likely cause problem for certain gRPC users. For details, + // refer to internal doc https://goo.gl/c2diBc + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern: + @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" + options:0 + error:&error]; + + NSString *customUserAgent = + [regex stringByReplacingMatchesInString:userAgent + options:0 + range:NSMakeRange(0, [userAgent length]) + withTemplate:@""]; + XCTAssertEqualObjects(customUserAgent, @"Foo"); + [recvInitialMd fulfill]; + } + messageCallback:^(id message) { + XCTAssertNotNil(message); + XCTAssertEqual([message length], 0, + @"Non-empty response received: %@", message); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + if (error) { + XCTFail(@"Finished with unexpected error: %@", error); + } else { + [completion fulfill]; + } + }] + callOptions:options]; + [call writeData:[NSData data]]; + [call start]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +- (void)getTokenWithHandler:(void (^)(NSString *token))handler { + dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + dispatch_sync(queue, ^{ + handler(@"test-access-token"); + }); +} + +- (void)testOAuthToken { + __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; + + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kEmptyCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = GRPCTransportTypeInsecure; + options.authTokenProvider = self; + __block GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + responseHandler:[[ClientTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:nil + messageCallback:nil + closeCallback:^(NSDictionary *trailingMetadata, + NSError *error) { + [completion fulfill]; + }] + callOptions:options]; + [call writeData:[NSData data]]; + [call start]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +- (void)testResponseSizeLimitExceeded { + __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; + + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kUnaryCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.responseSizeLimit = kSimpleDataLength; + options.transportType = GRPCTransportTypeInsecure; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit]; + request.responseSize = (int32_t)(options.responseSizeLimit * 2); + + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + responseHandler:[[ClientTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:nil + messageCallback:nil + closeCallback:^(NSDictionary *trailingMetadata, + NSError *error) { + XCTAssertNotNil(error, + @"Expecting non-nil error"); + XCTAssertEqual(error.code, + GRPCErrorCodeResourceExhausted); + [completion fulfill]; + }] + callOptions:options]; + [call writeData:[request data]]; + [call start]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +- (void)testIdempotentProtoRPC { + __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."]; + __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.responseSize = kSimpleDataLength; + request.fillUsername = YES; + request.fillOauthScope = YES; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kUnaryCallMethod.HTTPPath + safety:GRPCCallSafetyIdempotentRequest]; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = GRPCTransportTypeInsecure; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + NSData *data = (NSData *)message; + XCTAssertNotNil(data, @"nil value received as response."); + XCTAssertGreaterThan(data.length, 0, + @"Empty response received."); + RMTSimpleResponse *responseProto = + [RMTSimpleResponse parseFromData:data error:NULL]; + // We expect empty strings, not nil: + XCTAssertNotNil(responseProto.username, + @"Response's username is nil."); + XCTAssertNotNil(responseProto.oauthScope, + @"Response's OAuth scope is nil."); + [response fulfill]; + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", + error); + [completion fulfill]; + }] + callOptions:options]; + + [call start]; + [call writeData:[request data]]; + [call finish]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +- (void)testTimeout { + __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.timeout = 0.001; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kFullDuplexCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + responseHandler: + [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(NSData *data) { + XCTFail(@"Failure: response received; Expect: no response received."); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNotNil(error, + @"Failure: no error received; Expect: receive " + @"deadline exceeded."); + XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded); + [completion fulfill]; + }] + callOptions:options]; + + [call start]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +- (void)testTimeoutBackoffWithTimeout:(double)timeout Backoff:(double)backoff { + const double maxConnectTime = timeout > backoff ? timeout : backoff; + const double kMargin = 0.1; + + __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; + NSString *const kDummyAddress = [NSString stringWithFormat:@"127.0.0.1:10000"]; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kDummyAddress + path:@"/dummy/path" + safety:GRPCCallSafetyDefault]; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.connectMinTimeout = timeout; + options.connectInitialBackoff = backoff; + options.connectMaxBackoff = 0; + + NSDate *startTime = [NSDate date]; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(NSData *data) { + XCTFail(@"Received message. Should not reach here."); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNotNil(error, + @"Finished with no error; expecting error"); + XCTAssertLessThan( + [[NSDate date] timeIntervalSinceDate:startTime], + maxConnectTime + kMargin); + [completion fulfill]; + }] + callOptions:options]; + + [call start]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +- (void)testTimeoutBackoff1 { + [self testTimeoutBackoffWithTimeout:0.7 Backoff:0.4]; +} + +- (void)testTimeoutBackoff2 { + [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.8]; +} + +- (void)testCompression { + __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.expectCompressed = [RMTBoolValue message]; + request.expectCompressed.value = YES; + request.responseCompressed = [RMTBoolValue message]; + request.expectCompressed.value = YES; + request.responseSize = kSimpleDataLength; + request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; + GRPCRequestOptions *requestOptions = + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kUnaryCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = GRPCTransportTypeInsecure; + options.compressionAlgorithm = GRPCCompressGzip; + GRPCCall2 *call = [[GRPCCall2 alloc] + initWithRequestOptions:requestOptions + responseHandler: [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(NSData *data) { + NSError *error; + RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:data error:&error]; + XCTAssertNil(error, @"Error when parsing response: %@", error); + XCTAssertEqual(response.payload.body.length, kSimpleDataLength); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNil(error, @"Received failure: %@", error); + [completion fulfill]; + }] + + callOptions:options]; + + [call start]; + [call writeData:[request data]]; + [call finish]; + + [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; +} + +@end diff --git a/src/objective-c/tests/APIv2Tests/Info.plist b/src/objective-c/tests/APIv2Tests/Info.plist new file mode 100644 index 0000000000..6c40a6cd0c --- /dev/null +++ b/src/objective-c/tests/APIv2Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index bbe81502dc..727dc59ca1 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -86,65 +86,6 @@ static GRPCProtoMethod *kFullDuplexCallMethod; @end -// Convenience class to use blocks as callbacks -@interface ClientTestsBlockCallbacks : NSObject - -- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback - messageCallback:(void (^)(id))messageCallback - closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback; - -@end - -@implementation ClientTestsBlockCallbacks { - void (^_initialMetadataCallback)(NSDictionary *); - void (^_messageCallback)(id); - void (^_closeCallback)(NSDictionary *, NSError *); - dispatch_queue_t _dispatchQueue; -} - -- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback - messageCallback:(void (^)(id))messageCallback - closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback { - if ((self = [super init])) { - _initialMetadataCallback = initialMetadataCallback; - _messageCallback = messageCallback; - _closeCallback = closeCallback; - _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); - } - return self; -} - -- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { - dispatch_async(_dispatchQueue, ^{ - if (_initialMetadataCallback) { - _initialMetadataCallback(initialMetadata); - } - }); -} - -- (void)receivedRawMessage:(GPBMessage *_Nullable)message { - dispatch_async(_dispatchQueue, ^{ - if (_messageCallback) { - _messageCallback(message); - } - }); -} - -- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata - error:(NSError *_Nullable)error { - dispatch_async(_dispatchQueue, ^{ - if (_closeCallback) { - _closeCallback(trailingMetadata, error); - } - }); -} - -- (dispatch_queue_t)dispatchQueue { - return _dispatchQueue; -} - -@end - #pragma mark Tests /** @@ -296,55 +237,6 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- (void)testMetadataWithV2API { - __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."]; - - RMTSimpleRequest *request = [RMTSimpleRequest message]; - request.fillUsername = YES; - request.fillOauthScope = YES; - - GRPCRequestOptions *callRequest = - [[GRPCRequestOptions alloc] initWithHost:(NSString *)kRemoteSSLHost - path:kUnaryCallMethod.HTTPPath - safety:GRPCCallSafetyDefault]; - __block NSDictionary *init_md; - __block NSDictionary *trailing_md; - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.oauth2AccessToken = @"bogusToken"; - GRPCCall2 *call = [[GRPCCall2 alloc] - initWithRequestOptions:callRequest - responseHandler:[[ClientTestsBlockCallbacks alloc] - initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) { - init_md = initialMetadata; - } - messageCallback:^(id message) { - XCTFail(@"Received unexpected response."); - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - trailing_md = trailingMetadata; - if (error) { - XCTAssertEqual(error.code, 16, - @"Finished with unexpected error: %@", error); - XCTAssertEqualObjects(init_md, - error.userInfo[kGRPCHeadersKey]); - XCTAssertEqualObjects(trailing_md, - error.userInfo[kGRPCTrailersKey]); - NSString *challengeHeader = init_md[@"www-authenticate"]; - XCTAssertGreaterThan(challengeHeader.length, 0, - @"No challenge in response headers %@", - init_md); - [expectation fulfill]; - } - }] - callOptions:options]; - - [call start]; - [call writeData:[request data]]; - [call finish]; - - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; -} - - (void)testResponseMetadataKVO { __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; @@ -437,75 +329,6 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- (void)testUserAgentPrefixWithV2API { - __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; - __weak XCTestExpectation *recvInitialMd = - [self expectationWithDescription:@"Did not receive initial md."]; - - GRPCRequestOptions *request = [[GRPCRequestOptions alloc] initWithHost:kHostAddress - path:kEmptyCallMethod.HTTPPath - safety:GRPCCallSafetyDefault]; - NSDictionary *headers = - [NSDictionary dictionaryWithObjectsAndKeys:@"", @"x-grpc-test-echo-useragent", nil]; - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.transportType = GRPCTransportTypeInsecure; - options.userAgentPrefix = @"Foo"; - options.initialMetadata = headers; - GRPCCall2 *call = [[GRPCCall2 alloc] - initWithRequestOptions:request - responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^( - NSDictionary *initialMetadata) { - NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"]; - // Test the regex is correct - NSString *expectedUserAgent = @"Foo grpc-objc/"; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; - expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"]; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; - expectedUserAgent = [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "]; - expectedUserAgent = [expectedUserAgent - stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]]; - expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"]; - XCTAssertEqualObjects(userAgent, expectedUserAgent); - - NSError *error = nil; - // Change in format of user-agent field in a direction that does not match - // the regex will likely cause problem for certain gRPC users. For details, - // refer to internal doc https://goo.gl/c2diBc - NSRegularExpression *regex = [NSRegularExpression - regularExpressionWithPattern: - @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" - options:0 - error:&error]; - - NSString *customUserAgent = - [regex stringByReplacingMatchesInString:userAgent - options:0 - range:NSMakeRange(0, [userAgent length]) - withTemplate:@""]; - XCTAssertEqualObjects(customUserAgent, @"Foo"); - [recvInitialMd fulfill]; - } - messageCallback:^(id message) { - XCTAssertNotNil(message); - XCTAssertEqual([message length], 0, - @"Non-empty response received: %@", message); - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - if (error) { - XCTFail(@"Finished with unexpected error: %@", error); - } else { - [completion fulfill]; - } - }] - callOptions:options]; - [call writeData:[NSData data]]; - [call start]; - - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; -} - - (void)testTrailers { __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; @@ -597,52 +420,6 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- (void)testIdempotentProtoRPCWithV2API { - __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."]; - __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; - - RMTSimpleRequest *request = [RMTSimpleRequest message]; - request.responseSize = 100; - request.fillUsername = YES; - request.fillOauthScope = YES; - GRPCRequestOptions *requestOptions = - [[GRPCRequestOptions alloc] initWithHost:kHostAddress - path:kUnaryCallMethod.HTTPPath - safety:GRPCCallSafetyIdempotentRequest]; - - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.transportType = GRPCTransportTypeInsecure; - GRPCCall2 *call = [[GRPCCall2 alloc] - initWithRequestOptions:requestOptions - responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil - messageCallback:^(id message) { - NSData *data = (NSData *)message; - XCTAssertNotNil(data, @"nil value received as response."); - XCTAssertGreaterThan(data.length, 0, - @"Empty response received."); - RMTSimpleResponse *responseProto = - [RMTSimpleResponse parseFromData:data error:NULL]; - // We expect empty strings, not nil: - XCTAssertNotNil(responseProto.username, - @"Response's username is nil."); - XCTAssertNotNil(responseProto.oauthScope, - @"Response's OAuth scope is nil."); - [response fulfill]; - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", - error); - [completion fulfill]; - }] - callOptions:options]; - - [call start]; - [call writeData:[request data]]; - [call finish]; - - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; -} - - (void)testAlternateDispatchQueue { const int32_t kPayloadSize = 100; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -732,37 +509,6 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- (void)testTimeoutWithV2API { - __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; - - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.timeout = 0.001; - GRPCRequestOptions *requestOptions = - [[GRPCRequestOptions alloc] initWithHost:kHostAddress - path:kFullDuplexCallMethod.HTTPPath - safety:GRPCCallSafetyDefault]; - - GRPCCall2 *call = [[GRPCCall2 alloc] - initWithRequestOptions:requestOptions - responseHandler: - [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil - messageCallback:^(id data) { - XCTFail(@"Failure: response received; Expect: no response received."); - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - XCTAssertNotNil(error, - @"Failure: no error received; Expect: receive " - @"deadline exceeded."); - XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded); - [completion fulfill]; - }] - callOptions:options]; - - [call start]; - - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; -} - - (int)findFreePort { struct sockaddr_in addr; unsigned int addr_len = sizeof(addr); @@ -834,43 +580,6 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- (void)testTimeoutBackoffWithOptionsWithTimeout:(double)timeout Backoff:(double)backoff { - const double maxConnectTime = timeout > backoff ? timeout : backoff; - const double kMargin = 0.1; - - __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; - NSString *const kDummyAddress = [NSString stringWithFormat:@"127.0.0.1:10000"]; - GRPCRequestOptions *requestOptions = - [[GRPCRequestOptions alloc] initWithHost:kDummyAddress - path:@"/dummy/path" - safety:GRPCCallSafetyDefault]; - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.connectMinTimeout = timeout; - options.connectInitialBackoff = backoff; - options.connectMaxBackoff = 0; - - NSDate *startTime = [NSDate date]; - GRPCCall2 *call = [[GRPCCall2 alloc] - initWithRequestOptions:requestOptions - responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil - messageCallback:^(id data) { - XCTFail(@"Received message. Should not reach here."); - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - XCTAssertNotNil(error, - @"Finished with no error; expecting error"); - XCTAssertLessThan( - [[NSDate date] timeIntervalSinceDate:startTime], - maxConnectTime + kMargin); - [completion fulfill]; - }] - callOptions:options]; - - [call start]; - - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; -} - // The numbers of the following three tests are selected to be smaller than the default values of // initial backoff (1s) and min_connect_timeout (20s), so that if they fail we know the default // values fail to be overridden by the channel args. diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index e87aba235a..5df9d4e85b 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -17,6 +17,7 @@ GRPC_LOCAL_SRC = '../../..' InteropTestsMultipleChannels InteropTestsCallOptions UnitTests + APIv2Tests ).each do |target_name| target target_name do pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index 104fd0a4ea..6d1932b021 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; }; 5E0282E9215AA697007AC99D /* UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* UnitTests.m */; }; 5E0282EB215AA697007AC99D /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; + 5E10F5AA218CB0D2008BAB68 /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E10F5A9218CB0D2008BAB68 /* APIv2Tests.m */; }; 5E7D71AD210954A8001EA6BA /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; 5E7D71B5210B9EC9001EA6BA /* InteropTestsCallOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */; }; 5E7D71B7210B9EC9001EA6BA /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; @@ -68,6 +69,7 @@ BC111C80CBF7068B62869352 /* libPods-InteropTestsRemoteCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */; }; C3D6F4270A2FFF634D8849ED /* libPods-InteropTestsLocalCleartextCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */; }; CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */; }; + E7F4C80FC8FC667B7447BFE7 /* libPods-APIv2Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B6AD69CACF67505B0F028E92 /* libPods-APIv2Tests.a */; }; F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */; }; /* End PBXBuildFile section */ @@ -176,7 +178,9 @@ 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartextCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.debug.xcconfig"; sourceTree = ""; }; + 1286B30AD74CB64CD91FB17D /* Pods-APIv2Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-APIv2Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests.debug.xcconfig"; sourceTree = ""; }; 1295CCBD1082B4A7CFCED95F /* Pods-InteropTestsMultipleChannels.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsMultipleChannels.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsMultipleChannels/Pods-InteropTestsMultipleChannels.cronet.xcconfig"; sourceTree = ""; }; + 12B238CD1702393C2BA5DE80 /* Pods-APIv2Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-APIv2Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests.release.xcconfig"; sourceTree = ""; }; 14B09A58FEE53A7A6B838920 /* Pods-InteropTestsLocalSSL.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.cronet.xcconfig"; sourceTree = ""; }; 1588C85DEAF7FC0ACDEA4C02 /* Pods-InteropTestsLocalCleartext.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.test.xcconfig"; sourceTree = ""; }; 17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; sourceTree = ""; }; @@ -200,6 +204,7 @@ 4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.release.xcconfig"; sourceTree = ""; }; 4ADEA1C8BBE10D90940AC68E /* Pods-InteropTestsRemote.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.cronet.xcconfig"; sourceTree = ""; }; 51A275E86C141416ED63FF76 /* Pods-InteropTestsLocalCleartext.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.release.xcconfig"; sourceTree = ""; }; + 51F2A64B7AADBA1B225B132E /* Pods-APIv2Tests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-APIv2Tests.test.xcconfig"; path = "Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests.test.xcconfig"; sourceTree = ""; }; 553BBBED24E4162D1F769D65 /* Pods-InteropTestsLocalSSL.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.debug.xcconfig"; sourceTree = ""; }; 55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; sourceTree = ""; }; 573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; sourceTree = ""; }; @@ -207,6 +212,9 @@ 5E0282E6215AA697007AC99D /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5E0282E8215AA697007AC99D /* UnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnitTests.m; sourceTree = ""; }; 5E0282EA215AA697007AC99D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5E10F5A7218CB0D1008BAB68 /* APIv2Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APIv2Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E10F5A9218CB0D2008BAB68 /* APIv2Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = APIv2Tests.m; sourceTree = ""; }; + 5E10F5AB218CB0D2008BAB68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsCallOptions.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsCallOptions.m; sourceTree = ""; }; 5E7D71B6210B9EC9001EA6BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -254,6 +262,7 @@ 7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.release.xcconfig"; sourceTree = ""; }; 7BA53C6D224288D5870FE6F3 /* Pods-InteropTestsLocalCleartextCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; sourceTree = ""; }; 8B498B05C6DA0818B2FA91D4 /* Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; sourceTree = ""; }; + 8C233E85C3EB45B3CAE52EDF /* Pods-APIv2Tests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-APIv2Tests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests.cronet.xcconfig"; sourceTree = ""; }; 90E63AD3C4A1E3E6BC745096 /* Pods-ChannelTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.cronet.xcconfig"; sourceTree = ""; }; 943138072A9605B5B8DC1FC0 /* Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; sourceTree = ""; }; 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.test.xcconfig"; sourceTree = ""; }; @@ -266,6 +275,7 @@ AC414EF7A6BF76ED02B6E480 /* Pods-InteropTestsRemoteWithCronet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.release.xcconfig"; sourceTree = ""; }; AF3FC2CFFE7B0961823BC740 /* libPods-InteropTestsCallOptions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsCallOptions.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B226619DC4E709E0FFFF94B8 /* Pods-CronetUnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.test.xcconfig"; sourceTree = ""; }; + B6AD69CACF67505B0F028E92 /* libPods-APIv2Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-APIv2Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.debug.xcconfig"; sourceTree = ""; }; BED74BC8ABF9917C66175879 /* Pods-ChannelTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChannelTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-ChannelTests/Pods-ChannelTests.test.xcconfig"; sourceTree = ""; }; C17F57E5BCB989AB1C2F1F25 /* Pods-InteropTestsRemoteCFStream.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.test.xcconfig"; sourceTree = ""; }; @@ -303,6 +313,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E10F5A4218CB0D1008BAB68 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E7F4C80FC8FC667B7447BFE7 /* libPods-APIv2Tests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E7D71AF210B9EC8001EA6BA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -456,6 +474,7 @@ 355D0E30AD224763BC9519F4 /* libPods-InteropTestsMultipleChannels.a */, AF3FC2CFFE7B0961823BC740 /* libPods-InteropTestsCallOptions.a */, 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */, + B6AD69CACF67505B0F028E92 /* libPods-APIv2Tests.a */, ); name = Frameworks; sourceTree = ""; @@ -525,6 +544,10 @@ 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */, E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */, EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */, + 1286B30AD74CB64CD91FB17D /* Pods-APIv2Tests.debug.xcconfig */, + 51F2A64B7AADBA1B225B132E /* Pods-APIv2Tests.test.xcconfig */, + 8C233E85C3EB45B3CAE52EDF /* Pods-APIv2Tests.cronet.xcconfig */, + 12B238CD1702393C2BA5DE80 /* Pods-APIv2Tests.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -538,6 +561,15 @@ path = UnitTests; sourceTree = ""; }; + 5E10F5A8218CB0D1008BAB68 /* APIv2Tests */ = { + isa = PBXGroup; + children = ( + 5E10F5A9218CB0D2008BAB68 /* APIv2Tests.m */, + 5E10F5AB218CB0D2008BAB68 /* Info.plist */, + ); + path = APIv2Tests; + sourceTree = ""; + }; 5E7D71B3210B9EC9001EA6BA /* InteropTestsCallOptions */ = { isa = PBXGroup; children = ( @@ -604,6 +636,7 @@ 5EB2A2F62109284500EB4B69 /* InteropTestsMultipleChannels */, 5E7D71B3210B9EC9001EA6BA /* InteropTestsCallOptions */, 5E0282E7215AA697007AC99D /* UnitTests */, + 5E10F5A8218CB0D1008BAB68 /* APIv2Tests */, 635697C81B14FC11007A7283 /* Products */, 51E4650F34F854F41FF053B3 /* Pods */, 136D535E19727099B941D7B1 /* Frameworks */, @@ -629,6 +662,7 @@ 5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */, 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */, 5E0282E6215AA697007AC99D /* UnitTests.xctest */, + 5E10F5A7218CB0D1008BAB68 /* APIv2Tests.xctest */, ); name = Products; sourceTree = ""; @@ -681,6 +715,25 @@ productReference = 5E0282E6215AA697007AC99D /* UnitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 5E10F5A6218CB0D1008BAB68 /* APIv2Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E10F5B0218CB0D2008BAB68 /* Build configuration list for PBXNativeTarget "APIv2Tests" */; + buildPhases = ( + 031ADD72298D6C6979CB06DB /* [CP] Check Pods Manifest.lock */, + 5E10F5A3218CB0D1008BAB68 /* Sources */, + 5E10F5A4218CB0D1008BAB68 /* Frameworks */, + 5E10F5A5218CB0D1008BAB68 /* Resources */, + FBB92A8B11C52512E67791E8 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = APIv2Tests; + productName = APIv2Tests; + productReference = 5E10F5A7218CB0D1008BAB68 /* APIv2Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */ = { isa = PBXNativeTarget; buildConfigurationList = 5E7D71BA210B9EC9001EA6BA /* Build configuration list for PBXNativeTarget "InteropTestsCallOptions" */; @@ -990,6 +1043,10 @@ CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; }; + 5E10F5A6218CB0D1008BAB68 = { + CreatedOnToolsVersion = 10.0; + ProvisioningStyle = Automatic; + }; 5E7D71B1210B9EC8001EA6BA = { CreatedOnToolsVersion = 9.3; ProvisioningStyle = Automatic; @@ -1071,6 +1128,7 @@ 5EB2A2F42109284500EB4B69 /* InteropTestsMultipleChannels */, 5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */, 5E0282E5215AA697007AC99D /* UnitTests */, + 5E10F5A6218CB0D1008BAB68 /* APIv2Tests */, ); }; /* End PBXProject section */ @@ -1083,6 +1141,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E10F5A5218CB0D1008BAB68 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E7D71B0210B9EC8001EA6BA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1206,6 +1271,28 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 031ADD72298D6C6979CB06DB /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-APIv2Tests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 0617B5294978A95BEBBFF733 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1764,6 +1851,28 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + FBB92A8B11C52512E67791E8 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1775,6 +1884,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E10F5A3218CB0D1008BAB68 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E10F5AA218CB0D2008BAB68 /* APIv2Tests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E7D71AE210B9EC8001EA6BA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2098,6 +2215,141 @@ }; name = Release; }; + 5E10F5AC218CB0D2008BAB68 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1286B30AD74CB64CD91FB17D /* Pods-APIv2Tests.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5E10F5AD218CB0D2008BAB68 /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 51F2A64B7AADBA1B225B132E /* Pods-APIv2Tests.test.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Test; + }; + 5E10F5AE218CB0D2008BAB68 /* Cronet */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8C233E85C3EB45B3CAE52EDF /* Pods-APIv2Tests.cronet.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Cronet; + }; + 5E10F5AF218CB0D2008BAB68 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 12B238CD1702393C2BA5DE80 /* Pods-APIv2Tests.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 5E1228981E4D400F00E8504F /* Test */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3648,6 +3900,17 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5E10F5B0218CB0D2008BAB68 /* Build configuration list for PBXNativeTarget "APIv2Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E10F5AC218CB0D2008BAB68 /* Debug */, + 5E10F5AD218CB0D2008BAB68 /* Test */, + 5E10F5AE218CB0D2008BAB68 /* Cronet */, + 5E10F5AF218CB0D2008BAB68 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 5E7D71BA210B9EC9001EA6BA /* Build configuration list for PBXNativeTarget "InteropTestsCallOptions" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme new file mode 100644 index 0000000000..b444ddc2b6 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index 118220ce4b..e8c3e6ec2a 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -183,4 +183,14 @@ xcodebuild \ | egrep -v '^$' \ | egrep -v "(GPBDictionary|GPBArray)" - +echo "TIME: $(date)" +xcodebuild \ + -workspace Tests.xcworkspace \ + -scheme APIv2Tests \ + -destination name="iPhone 8" \ + test \ + | egrep -v "$XCODEBUILD_FILTER" \ + | egrep -v '^$' \ + | egrep -v "(GPBDictionary|GPBArray)" - + exit 0 -- cgit v1.2.3 From 6b8f0ceae8f581cfd63b40c4e2ccab95783081ae Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 10:15:20 -0800 Subject: A few nits --- src/objective-c/GRPCClient/GRPCCall+OAuth2.h | 2 +- src/objective-c/GRPCClient/GRPCCall.h | 4 ++-- src/objective-c/GRPCClient/GRPCCall.m | 9 +++++++-- src/objective-c/ProtoRPC/ProtoRPC.h | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h index 3054bfc5a7..60cdc50bfd 100644 --- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h @@ -24,7 +24,7 @@ @interface GRPCCall (OAuth2) @property(atomic, copy) NSString* oauth2AccessToken; -@property(atomic, readonly) NSString* oauth2ChallengeHeader; +@property(atomic, copy, readonly) NSString* oauth2ChallengeHeader; @property(atomic, strong) id tokenProvider; @end diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index a1f139fc18..4f0660d203 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -196,7 +196,7 @@ extern NSString *const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype) new NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; /** Initialize with all properties. */ - (instancetype)initWithHost:(NSString *)host @@ -224,7 +224,7 @@ extern NSString *const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype) new NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; /** * Designated initializer for a call. diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 2abc0fe8f3..2f727e62be 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -67,6 +67,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; @implementation GRPCRequestOptions - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { + NSAssert(host.length != 0 && path.length != 0, @"Host and Path cannot be empty"); if ((self = [super init])) { _host = [host copy]; _path = [path copy]; @@ -90,7 +91,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; /** The handler of responses. */ id _handler; - // Thread safety of ivars below are protected by _dispatcheQueue. + // Thread safety of ivars below are protected by _dispatchQueue. /** * Make use of legacy GRPCCall to make calls. Nullified when call is finished. @@ -121,7 +122,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; if ((self = [super init])) { _requestOptions = [requestOptions copy]; - _callOptions = [callOptions copy]; + if (callOptions == nil) { + _callOptions = [[GRPCCallOptions alloc] init]; + } else { + _callOptions = [callOptions copy]; + } _handler = responseHandler; _initialMetadataPublished = NO; _pipe = [GRXBufferedPipe pipe]; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index b0f4ced99e..3d137a53ff 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -66,7 +66,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -+ (instancetype) new NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; /** * Users should not use this initializer directly. Call objects will be created, initialized, and @@ -92,7 +92,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -+ (instancetype) new NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; /** * Users should not use this initializer directly. Call objects will be created, initialized, and -- cgit v1.2.3 From b496e3a2663824c22806b7ee7b1423c806ecc61a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 11:07:03 -0800 Subject: On finish, clean _handler and _call independently --- src/objective-c/GRPCClient/GRPCCall.m | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 2f727e62be..af14193581 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -184,6 +184,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; } completionHandler:^(NSError *errorOrNil) { dispatch_async(self->_dispatchQueue, ^{ + if (self->_call) { + [self->_pipe writesFinishedWithError:nil]; + self->_call = nil; + self->_pipe = nil; + } if (self->_handler) { if (!self->_initialMetadataPublished) { self->_initialMetadataPublished = YES; @@ -193,12 +198,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; - - if (self->_call) { - [self->_pipe writesFinishedWithError:nil]; - self->_call = nil; - self->_pipe = nil; - } } }); }]; -- cgit v1.2.3 From 739760cdc8a6625fe93f4f0312d84305052b0d09 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 11:22:51 -0800 Subject: More comment --- src/objective-c/GRPCClient/GRPCCall.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index af14193581..9be0554ff9 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -185,6 +185,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; completionHandler:^(NSError *errorOrNil) { dispatch_async(self->_dispatchQueue, ^{ if (self->_call) { + // Clean up the request writers. This should have no effect to _call since its + // response writeable is already nullified. [self->_pipe writesFinishedWithError:nil]; self->_call = nil; self->_pipe = nil; -- cgit v1.2.3 From 24265b03ac5c6ace73916f3bc3a847abf1c64c33 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 11:31:48 -0800 Subject: Clarify cancel before call is started --- src/objective-c/GRPCClient/GRPCCall.h | 1 + src/objective-c/GRPCClient/GRPCCall.m | 1 + 2 files changed, 2 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 4f0660d203..f713262b64 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -245,6 +245,7 @@ extern NSString *const kGRPCTrailersKey; /** * Starts the call. This function should only be called once; additional calls will be discarded. + * Invokes after calling cancel: are discarded. */ - (void)start; diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 9be0554ff9..5ce361300d 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -209,6 +209,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancel { dispatch_async(_dispatchQueue, ^{ + self->_started = YES; if (self->_call) { [self->_call cancel]; self->_call = nil; -- cgit v1.2.3 From 9558618182aa817ad5aa9885f1fe12003ee1a93e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 11:37:41 -0800 Subject: Check if call is cancelled --- src/objective-c/GRPCClient/GRPCCall.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 5ce361300d..1338c1edd6 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -237,7 +237,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)writeData:(NSData *)data { dispatch_async(_dispatchQueue, ^{ - [self->_pipe writeValue:data]; + if (self->_call) { + [self->_pipe writeValue:data]; + } }); } -- cgit v1.2.3 From b3b98ba4a29f434541355e026765938998c22da4 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 12:09:46 -0800 Subject: test fix --- src/objective-c/tests/GRPCClientTests.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 727dc59ca1..834bf6d661 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -585,12 +585,10 @@ static GRPCProtoMethod *kFullDuplexCallMethod; // values fail to be overridden by the channel args. - (void)testTimeoutBackoff1 { [self testTimeoutBackoffWithTimeout:0.7 Backoff:0.3]; - [self testTimeoutBackoffWithOptionsWithTimeout:0.7 Backoff:0.4]; } - (void)testTimeoutBackoff2 { [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.7]; - [self testTimeoutBackoffWithOptionsWithTimeout:0.3 Backoff:0.8]; } - (void)testErrorDebugInformation { -- cgit v1.2.3 From 1be316e5641db3192a3f7b276e3926d8da17c62a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 14:12:14 -0800 Subject: Remove check in cancel --- src/objective-c/GRPCClient/GRPCCall.h | 5 ++--- src/objective-c/GRPCClient/GRPCCall.m | 42 ++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index f713262b64..260305a989 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -244,8 +244,7 @@ extern NSString *const kGRPCTrailersKey; responseHandler:(id)responseHandler; /** - * Starts the call. This function should only be called once; additional calls will be discarded. - * Invokes after calling cancel: are discarded. + * Starts the call. This function must only be called once for each instance. */ - (void)start; @@ -263,7 +262,7 @@ extern NSString *const kGRPCTrailersKey; /** * Finish the RPC request and half-close the call. The server may still send messages and/or - * trailers to the client. + * trailers to the client. The method must only be called once and after start is called. */ - (void)finish; diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 1338c1edd6..9f8339eb60 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -105,6 +105,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_queue_t _dispatchQueue; /** Flags whether call has started. */ BOOL _started; + /** Flags whether call has been canceled. */ + BOOL _canceled; + /** Flags whether call has been finished. */ } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -140,6 +143,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); _started = NO; + _canceled = NO; } return self; @@ -153,9 +157,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)start { dispatch_async(_dispatchQueue, ^{ - if (self->_started) { - return; - } + NSAssert(!self->_started, @"Call already started."); + NSAssert(!self->_canceled, @"Call already canceled."); self->_started = YES; if (!self->_callOptions) { self->_callOptions = [[GRPCCallOptions alloc] init]; @@ -184,13 +187,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; } completionHandler:^(NSError *errorOrNil) { dispatch_async(self->_dispatchQueue, ^{ - if (self->_call) { - // Clean up the request writers. This should have no effect to _call since its - // response writeable is already nullified. - [self->_pipe writesFinishedWithError:nil]; - self->_call = nil; - self->_pipe = nil; - } if (self->_handler) { if (!self->_initialMetadataPublished) { self->_initialMetadataPublished = YES; @@ -201,6 +197,15 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; } + // Clearing _call must happen *after* dispatching close in order to get trailing + // metadata from _call. + if (self->_call) { + // Clean up the request writers. This should have no effect to _call since its + // response writeable is already nullified. + [self->_pipe writesFinishedWithError:nil]; + self->_call = nil; + self->_pipe = nil; + } }); }]; [self->_call startWithWriteable:responseWriteable]; @@ -209,7 +214,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancel { dispatch_async(_dispatchQueue, ^{ - self->_started = YES; + NSAssert(!self->_canceled, @"Call already canceled."); if (self->_call) { [self->_call cancel]; self->_call = nil; @@ -237,6 +242,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)writeData:(NSData *)data { dispatch_async(_dispatchQueue, ^{ + NSAssert(!self->_canceled, @"Call arleady canceled."); + NSAssert(!self->_finished, @"Call is half-closed before sending data."); if (self->_call) { [self->_pipe writeValue:data]; } @@ -245,6 +252,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)finish { dispatch_async(_dispatchQueue, ^{ + NSAssert(self->started, @"Call not started."); + NSAssert(!self->_canceled, @"Call arleady canceled."); + NSAssert(!self->_finished, @"Call already half-closed."); if (self->_call) { [self->_pipe writesFinishedWithError:nil]; } @@ -265,9 +275,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - NSDictionary *trailers = _call.responseTrailers; if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [_handler closedWithTrailingMetadata:trailers error:error]; + [_handler closedWithTrailingMetadata:_call.responseTrailers error:error]; } } @@ -464,11 +473,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancel { @synchronized(self) { - if (!self.isWaitingForToken) { - [self cancelCall]; - } else { - self.isWaitingForToken = NO; - } + [self cancelCall]; + self.isWaitingForToken = NO; } [self maybeFinishWithError:[NSError -- cgit v1.2.3 From 515941ae1899ca125e8da77c3031d3f0471488ff Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 16:04:56 -0800 Subject: copy _requestHeaders in GRPCCall --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 9f8339eb60..c10fe7c134 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -578,7 +578,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; break; } - NSMutableDictionary *headers = _requestHeaders; + NSMutableDictionary *headers = [_requestHeaders copy]; NSString *fetchedOauth2AccessToken; @synchronized(self) { fetchedOauth2AccessToken = _fetchedOauth2AccessToken; -- cgit v1.2.3 From d635d9f9f98bc374c0b3502bbcc8f707c27d7038 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 16:43:58 -0800 Subject: fix some threading issues --- src/objective-c/GRPCClient/GRPCCall.m | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index c10fe7c134..b3bddf08a0 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -468,7 +468,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancelCall { // Can be called from any thread, any number of times. - [_wrappedCall cancel]; + @synchronized (self) { + [_wrappedCall cancel]; + } } - (void)cancel { @@ -730,17 +732,21 @@ const char *kCFStreamVarName = "grpc_cfstream"; _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; - _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions]; - if (_wrappedCall == nil) { + GRPCWrappedCall *wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions]; + if (wrappedCall == nil) { [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeUnavailable userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to create call or channel." - }]]; + NSLocalizedDescriptionKey : + @"Failed to create call or channel." + }]]; return; } + @synchronized (self) { + _wrappedCall = wrappedCall; + } + [self sendHeaders]; [self invokeCall]; -- cgit v1.2.3 From d40e828d53cdb983255e0406261fed71710ba361 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 17:08:26 -0800 Subject: NSInteger->NSUInteger --- src/objective-c/GRPCClient/GRPCCallOptions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 77fde371bc..bb8a1d251a 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -34,7 +34,7 @@ typedef NS_ENUM(NSUInteger, GRPCCallSafety) { }; // Compression algorithm to be used by a gRPC call -typedef NS_ENUM(NSInteger, GRPCCompressionAlgorithm) { +typedef NS_ENUM(NSUInteger, GRPCCompressionAlgorithm) { GRPCCompressNone = 0, GRPCCompressDeflate, GRPCCompressGzip, @@ -45,7 +45,7 @@ typedef NS_ENUM(NSInteger, GRPCCompressionAlgorithm) { typedef GRPCCompressionAlgorithm GRPCCompressAlgorithm; /** The transport to be used by a gRPC call */ -typedef NS_ENUM(NSInteger, GRPCTransportType) { +typedef NS_ENUM(NSUInteger, GRPCTransportType) { GRPCTransportTypeDefault = 0, /** gRPC internal HTTP/2 stack with BoringSSL */ GRPCTransportTypeChttp2BoringSSL = 0, -- cgit v1.2.3 From ae623ea5b65ff6060d0b8a63fdf3f26560118720 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 17:32:22 -0800 Subject: Polish isEqual of options --- src/objective-c/GRPCClient/GRPCCallOptions.m | 43 ++++++++++------------ .../GRPCClient/private/GRPCChannelPool.m | 2 +- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index c7096cf1cf..beea9ce46e 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -44,6 +44,17 @@ static const id kDefaultLogContext = nil; static NSString *const kDefaultChannelPoolDomain = nil; static const NSUInteger kDefaultChannelID = 0; +// Check if two objects are equal. Returns YES if both are nil; +BOOL areObjectsEqual(id obj1, id obj2) { + if (obj1 == obj2) { + return YES; + } + if (obj1 == nil || obj2 == nil) { + return NO; + } + return [obj1 isEqual:obj2]; +} + @implementation GRPCCallOptions { @protected NSString *_serverAuthority; @@ -232,9 +243,8 @@ static const NSUInteger kDefaultChannelID = 0; } - (BOOL)hasChannelOptionsEqualTo:(GRPCCallOptions *)callOptions { - if (!(callOptions.userAgentPrefix == _userAgentPrefix || - [callOptions.userAgentPrefix isEqualToString:_userAgentPrefix])) - return NO; + if (callOptions == nil) return NO; + if (!areObjectsEqual(callOptions.userAgentPrefix, _userAgentPrefix)) return NO; if (!(callOptions.responseSizeLimit == _responseSizeLimit)) return NO; if (!(callOptions.compressionAlgorithm == _compressionAlgorithm)) return NO; if (!(callOptions.retryEnabled == _retryEnabled)) return NO; @@ -243,27 +253,14 @@ static const NSUInteger kDefaultChannelID = 0; if (!(callOptions.connectMinTimeout == _connectMinTimeout)) return NO; if (!(callOptions.connectInitialBackoff == _connectInitialBackoff)) return NO; if (!(callOptions.connectMaxBackoff == _connectMaxBackoff)) return NO; - if (!(callOptions.additionalChannelArgs == _additionalChannelArgs || - [callOptions.additionalChannelArgs isEqualToDictionary:_additionalChannelArgs])) - return NO; - if (!(callOptions.PEMRootCertificates == _PEMRootCertificates || - [callOptions.PEMRootCertificates isEqualToString:_PEMRootCertificates])) - return NO; - if (!(callOptions.PEMPrivateKey == _PEMPrivateKey || - [callOptions.PEMPrivateKey isEqualToString:_PEMPrivateKey])) - return NO; - if (!(callOptions.PEMCertChain == _PEMCertChain || - [callOptions.PEMCertChain isEqualToString:_PEMCertChain])) - return NO; - if (!(callOptions.hostNameOverride == _hostNameOverride || - [callOptions.hostNameOverride isEqualToString:_hostNameOverride])) - return NO; + if (!areObjectsEqual(callOptions.additionalChannelArgs, _additionalChannelArgs)) return NO; + if (!areObjectsEqual(callOptions.PEMRootCertificates, _PEMRootCertificates)) return NO; + if (!areObjectsEqual(callOptions.PEMPrivateKey, _PEMPrivateKey)) return NO; + if (!areObjectsEqual(callOptions.PEMCertChain, _PEMCertChain)) return NO; + if (!areObjectsEqual(callOptions.hostNameOverride, _hostNameOverride)) return NO; if (!(callOptions.transportType == _transportType)) return NO; - if (!(callOptions.logContext == _logContext || [callOptions.logContext isEqual:_logContext])) - return NO; - if (!(callOptions.channelPoolDomain == _channelPoolDomain || - [callOptions.channelPoolDomain isEqualToString:_channelPoolDomain])) - return NO; + if (!areObjectsEqual(callOptions.logContext, _logContext)) return NO; + if (!areObjectsEqual(callOptions.channelPoolDomain, _channelPoolDomain)) return NO; if (!(callOptions.channelID == _channelID)) return NO; return YES; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 56de8a0d6f..627bbab3c0 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -151,7 +151,7 @@ extern const char *kCFStreamVarName; return NO; } GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; - if (!(obj.host == _host || [obj.host isEqualToString:_host])) return NO; + if (!(obj.host == _host || (_host != nil && [obj.host isEqualToString:_host]))) return NO; if (!(obj.callOptions == _callOptions || [obj.callOptions hasChannelOptionsEqualTo:_callOptions])) return NO; -- cgit v1.2.3 From bb5e55e86896ff353010db58bc6381436e11c4a5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 17:37:47 -0800 Subject: remove extra copy --- src/objective-c/GRPCClient/GRPCCallOptions.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index beea9ce46e..696e81703f 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -360,7 +360,7 @@ BOOL areObjectsEqual(id obj1, id obj2) { connectMinTimeout:_connectMinTimeout connectInitialBackoff:_connectInitialBackoff connectMaxBackoff:_connectMaxBackoff - additionalChannelArgs:[_additionalChannelArgs copy] + additionalChannelArgs:_additionalChannelArgs PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey PEMCertChain:_PEMCertChain -- cgit v1.2.3 From d8e7a6c6f1269eedec3f7b175ac85ed89e6e490e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 17:38:21 -0800 Subject: hash: -> .hash --- src/objective-c/GRPCClient/GRPCCallOptions.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 696e81703f..3e0dbbf7e4 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -283,7 +283,7 @@ BOOL areObjectsEqual(id obj1, id obj2) { result ^= _PEMCertChain.hash; result ^= _hostNameOverride.hash; result ^= _transportType; - result ^= [_logContext hash]; + result ^= _logContext.hash; result ^= _channelPoolDomain.hash; result ^= _channelID; -- cgit v1.2.3 From a0f5db15815d3ec5b2ad3b781cca5e2eb6468824 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 17:42:30 -0800 Subject: Rename GRPCCallOptions+internal->GRPCCallOptions+Internal --- gRPC.podspec | 2 +- .../GRPCClient/internal/GRPCCallOptions+Internal.h | 39 ++++++++++++++++++++++ .../GRPCClient/internal/GRPCCallOptions+internal.h | 39 ---------------------- templates/gRPC.podspec.template | 2 +- 4 files changed, 41 insertions(+), 41 deletions(-) create mode 100644 src/objective-c/GRPCClient/internal/GRPCCallOptions+Internal.h delete mode 100644 src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h diff --git a/gRPC.podspec b/gRPC.podspec index 47a130d12d..d8aa997e7c 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -58,7 +58,7 @@ Pod::Spec.new do |s| ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" ss.exclude_files = "#{src_dir}/GRPCCall+GID.{h,m}" - ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/GRPCCallOptions+Internal.h" + ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/*.h" ss.dependency 'gRPC-Core', version end diff --git a/src/objective-c/GRPCClient/internal/GRPCCallOptions+Internal.h b/src/objective-c/GRPCClient/internal/GRPCCallOptions+Internal.h new file mode 100644 index 0000000000..eb691b3acb --- /dev/null +++ b/src/objective-c/GRPCClient/internal/GRPCCallOptions+Internal.h @@ -0,0 +1,39 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import "../GRPCCallOptions.h" + +@interface GRPCCallOptions () + +/** + * Parameter used for internal logging. + */ +@property(readonly) id logContext; + +@end + +@interface GRPCMutableCallOptions () + +/** + * Parameter used for internal logging. + */ +@property(readwrite) id logContext; + +@end diff --git a/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h b/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h deleted file mode 100644 index eb691b3acb..0000000000 --- a/src/objective-c/GRPCClient/internal/GRPCCallOptions+internal.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import - -#import "../GRPCCallOptions.h" - -@interface GRPCCallOptions () - -/** - * Parameter used for internal logging. - */ -@property(readonly) id logContext; - -@end - -@interface GRPCMutableCallOptions () - -/** - * Parameter used for internal logging. - */ -@property(readwrite) id logContext; - -@end diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template index a3ed1d7858..593d277e5b 100644 --- a/templates/gRPC.podspec.template +++ b/templates/gRPC.podspec.template @@ -60,7 +60,7 @@ ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" ss.exclude_files = "#{src_dir}/GRPCCall+GID.{h,m}" - ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/GRPCCallOptions+Internal.h" + ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/*.h" ss.dependency 'gRPC-Core', version end -- cgit v1.2.3 From ab9510560781dd2f27608e694518f67b7d425d9a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 6 Nov 2018 17:46:22 -0800 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.h | 4 +-- src/objective-c/GRPCClient/GRPCCall.m | 13 +++++----- src/objective-c/ProtoRPC/ProtoRPC.h | 4 +-- src/objective-c/tests/APIv2Tests/APIv2Tests.m | 35 ++++++++++++++------------- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 260305a989..bde69f01c5 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -196,7 +196,7 @@ extern NSString *const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** Initialize with all properties. */ - (instancetype)initWithHost:(NSString *)host @@ -224,7 +224,7 @@ extern NSString *const kGRPCTrailersKey; - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** * Designated initializer for a call. diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index b3bddf08a0..321a0bd1bd 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -468,7 +468,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancelCall { // Can be called from any thread, any number of times. - @synchronized (self) { + @synchronized(self) { [_wrappedCall cancel]; } } @@ -732,18 +732,19 @@ const char *kCFStreamVarName = "grpc_cfstream"; _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; - GRPCWrappedCall *wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions]; + GRPCWrappedCall *wrappedCall = + [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions]; if (wrappedCall == nil) { [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeUnavailable userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to create call or channel." - }]]; + NSLocalizedDescriptionKey : + @"Failed to create call or channel." + }]]; return; } - @synchronized (self) { + @synchronized(self) { _wrappedCall = wrappedCall; } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 3d137a53ff..b0f4ced99e 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -66,7 +66,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** * Users should not use this initializer directly. Call objects will be created, initialized, and @@ -92,7 +92,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; /** * Users should not use this initializer directly. Call objects will be created, initialized, and diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index 7fc353391f..d681163419 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -449,28 +449,29 @@ static const NSTimeInterval kTestTimeout = 16; request.responseSize = kSimpleDataLength; request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; GRPCRequestOptions *requestOptions = - [[GRPCRequestOptions alloc] initWithHost:kHostAddress - path:kUnaryCallMethod.HTTPPath - safety:GRPCCallSafetyDefault]; + [[GRPCRequestOptions alloc] initWithHost:kHostAddress + path:kUnaryCallMethod.HTTPPath + safety:GRPCCallSafetyDefault]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.transportType = GRPCTransportTypeInsecure; options.compressionAlgorithm = GRPCCompressGzip; GRPCCall2 *call = [[GRPCCall2 alloc] - initWithRequestOptions:requestOptions - responseHandler: [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil - messageCallback:^(NSData *data) { - NSError *error; - RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:data error:&error]; - XCTAssertNil(error, @"Error when parsing response: %@", error); - XCTAssertEqual(response.payload.body.length, kSimpleDataLength); - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - XCTAssertNil(error, @"Received failure: %@", error); - [completion fulfill]; - }] - - callOptions:options]; + initWithRequestOptions:requestOptions + responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(NSData *data) { + NSError *error; + RMTSimpleResponse *response = + [RMTSimpleResponse parseFromData:data error:&error]; + XCTAssertNil(error, @"Error when parsing response: %@", error); + XCTAssertEqual(response.payload.body.length, kSimpleDataLength); + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNil(error, @"Received failure: %@", error); + [completion fulfill]; + }] + + callOptions:options]; [call start]; [call writeData:[request data]]; -- cgit v1.2.3 From 9e5d7476ac48b82ee8ce7855c30d3aa5edab5280 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 7 Nov 2018 11:32:12 -0800 Subject: nit build fix --- src/objective-c/GRPCClient/GRPCCallOptions.m | 4 ++-- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 2 +- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 3e0dbbf7e4..ecb517762b 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -17,7 +17,7 @@ */ #import "GRPCCallOptions.h" -#import "internal/GRPCCallOptions+internal.h" +#import "internal/GRPCCallOptions+Internal.h" // The default values for the call options. static NSString *const kDefaultServerAuthority = nil; @@ -77,7 +77,7 @@ BOOL areObjectsEqual(id obj1, id obj2) { NSString *_PEMCertChain; GRPCTransportType _transportType; NSString *_hostNameOverride; - id _logContext; + id _logContext; NSString *_channelPoolDomain; NSUInteger _channelID; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 627bbab3c0..b4a589ae83 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -18,7 +18,7 @@ #import -#import "../internal/GRPCCallOptions+internal.h" +#import "../internal/GRPCCallOptions+Internal.h" #import "GRPCChannel.h" #import "GRPCChannelFactory.h" #import "GRPCChannelPool.h" diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 8a59bd43d7..a67162c101 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -25,7 +25,7 @@ #include #include -#import "../internal/GRPCCallOptions+internal.h" +#import "../internal/GRPCCallOptions+Internal.h" #import "GRPCChannelFactory.h" #import "GRPCCompletionQueue.h" #import "GRPCConnectivityMonitor.h" -- cgit v1.2.3 From c9c060c52da12cc55bbd383b1544260ad665dbab Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 7 Nov 2018 11:32:30 -0800 Subject: nit fixes in ChannelArgsUtil --- src/objective-c/GRPCClient/private/ChannelArgsUtil.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m index b8342a79e7..d9e44b557d 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -31,7 +31,7 @@ static void *copy_pointer_arg(void *p) { static void destroy_pointer_arg(void *p) { // Decrease ref count to the object when destroying - CFRelease((CFTreeRef)p); + CFRelease((CFTypeRef)p); } static int cmp_pointer_arg(void *p, void *q) { return p == q; } @@ -52,7 +52,7 @@ void GRPCFreeChannelArgs(grpc_channel_args *channel_args) { } grpc_channel_args *GRPCBuildChannelArgs(NSDictionary *dictionary) { - if (!dictionary) { + if (dictionary.count == 0) { return NULL; } -- cgit v1.2.3 From d72d5b2c8eaa8a434a7db4624fe6a45bc0d6bde4 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 8 Nov 2018 15:33:27 -0800 Subject: Some nit fixes --- src/objective-c/GRPCClient/GRPCCall.m | 4 +++- src/objective-c/GRPCClient/private/GRPCChannel.m | 21 ++++++++++++--------- .../GRPCClient/private/GRPCChannelPool.h | 2 -- .../GRPCClient/private/GRPCChannelPool.m | 1 + 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 321a0bd1bd..9b9b4f9547 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -108,6 +108,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; /** Flags whether call has been canceled. */ BOOL _canceled; /** Flags whether call has been finished. */ + BOOL _finished; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -144,6 +145,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); _started = NO; _canceled = NO; + _finished = YES; } return self; @@ -252,7 +254,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)finish { dispatch_async(_dispatchQueue, ^{ - NSAssert(self->started, @"Call not started."); + NSAssert(self->_started, @"Call not started."); NSAssert(!self->_canceled, @"Call arleady canceled."); NSAssert(!self->_finished, @"Call already half-closed."); if (self->_call) { diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 0ca2a35992..773f4261d7 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -53,7 +53,7 @@ static GRPCChannelPool *gChannelPool; /** Reduce call ref count to the channel and maybe set the timer. */ - (void)unrefChannel; -/** Disconnect the channel immediately. */ +/** Disconnect the channel. Any further ref/unref are discarded. */ - (void)disconnect; @end @@ -67,9 +67,8 @@ static GRPCChannelPool *gChannelPool; dispatch_queue_t _dispatchQueue; /** - * Date and time when last timer is scheduled. When a timer is fired, if - * _lastDispatch + _destroyDelay < now, it can be determined that another timer is scheduled after - * schedule of the current timer, hence the current one should be discarded. + * Date and time when last timer is scheduled. If a firing timer's scheduled date is different + * from this, it is discarded. */ NSDate *_lastDispatch; } @@ -113,7 +112,7 @@ static GRPCChannelPool *gChannelPool; dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)self->_destroyDelay * NSEC_PER_SEC); dispatch_after(delay, self->_dispatchQueue, ^{ - [self timerFireWithScheduleDate:now]; + [self timedDisconnectWithScheduleDate:now]; }); } } @@ -131,7 +130,7 @@ static GRPCChannelPool *gChannelPool; }); } -- (void)timerFireWithScheduleDate:(NSDate *)scheduleDate { +- (void)timedDisconnectWithScheduleDate:(NSDate *)scheduleDate { dispatch_async(_dispatchQueue, ^{ if (self->_disconnected || self->_lastDispatch != scheduleDate) { return; @@ -183,6 +182,8 @@ static GRPCChannelPool *gChannelPool; grpc_slice_unref(host_slice); } grpc_slice_unref(path_slice); + } else { + NSAssert(self->_unmanagedChannel != nil, @"Invalid channeg."); } }); return call; @@ -255,10 +256,9 @@ static GRPCChannelPool *gChannelPool; } + (nullable instancetype)createChannelWithConfiguration:(GRPCChannelConfiguration *)config { + NSAssert(config != nil, @"configuration cannot be empty"); NSString *host = config.host; - if (host.length == 0) { - return nil; - } + NSAssert(host.length != 0, @"host cannot be nil"); NSDictionary *channelArgs; if (config.callOptions.additionalChannelArgs.count != 0) { @@ -287,6 +287,9 @@ static GRPCChannelPool *gChannelPool; GRPCChannelConfiguration *channelConfig = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; + if (channelConfig == nil) { + return nil; + } return [gChannelPool channelWithConfiguration:channelConfig]; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 2244361df2..f99c0ba4dc 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -57,8 +57,6 @@ NS_ASSUME_NONNULL_BEGIN */ @interface GRPCChannelPool : NSObject -- (instancetype)init; - /** * Return a channel with a particular configuration. If the channel does not exist, execute \a * createChannel then add it in the pool. If the channel exists, increase its reference count. diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index b4a589ae83..1bf2a5c563 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -192,6 +192,7 @@ extern const char *kCFStreamVarName; } - (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration { + NSAssert(configuration != nil, @"Must has a configuration"); GRPCChannel *channel; @synchronized(self) { if ([_channelPool objectForKey:configuration]) { -- cgit v1.2.3 From 37dbad80d5254f9bf17076d12b22b7a081e6e9dc Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 8 Nov 2018 22:01:10 -0800 Subject: Refactor channel pool --- src/objective-c/GRPCClient/GRPCCall+ChannelArg.m | 4 +- src/objective-c/GRPCClient/private/GRPCChannel.h | 69 +++- src/objective-c/GRPCClient/private/GRPCChannel.m | 397 +++++++++++---------- .../GRPCClient/private/GRPCChannelPool.h | 55 ++- .../GRPCClient/private/GRPCChannelPool.m | 215 +++-------- .../GRPCClient/private/GRPCWrappedCall.m | 24 +- .../tests/ChannelTests/ChannelPoolTest.m | 161 +++++---- src/objective-c/tests/ChannelTests/ChannelTests.m | 97 +++-- 8 files changed, 482 insertions(+), 540 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m index d01d0c0d4f..971c2803e2 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m @@ -18,7 +18,7 @@ #import "GRPCCall+ChannelArg.h" -#import "private/GRPCChannel.h" +#import "private/GRPCChannelPool.h" #import "private/GRPCHost.h" #import @@ -36,7 +36,7 @@ } + (void)closeOpenConnections { - [GRPCChannel closeOpenConnections]; + [GRPCChannelPool closeOpenConnections]; } + (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm forhost:(nonnull NSString *)host { diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index e1bf8fb1af..bbe0ba5390 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -20,11 +20,37 @@ #include +@protocol GRPCChannelFactory; + @class GRPCCompletionQueue; @class GRPCCallOptions; @class GRPCChannelConfiguration; struct grpc_channel_credentials; +NS_ASSUME_NONNULL_BEGIN + +/** Caching signature of a channel. */ +@interface GRPCChannelConfiguration : NSObject + +/** The host that this channel is connected to. */ +@property(copy, readonly) NSString *host; + +/** + * Options of the corresponding call. Note that only the channel-related options are of interest to + * this class. + */ +@property(strong, readonly) GRPCCallOptions *callOptions; + +/** Acquire the factory to generate a new channel with current configurations. */ +@property(readonly) id channelFactory; + +/** Acquire the dictionary of channel args with current configurations. */ +@property(copy, readonly) NSDictionary *channelArgs; + +- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; + +@end + /** * Each separate instance of this class represents at least one TCP connection to the provided host. */ @@ -35,40 +61,45 @@ struct grpc_channel_credentials; + (nullable instancetype) new NS_UNAVAILABLE; /** - * Returns a channel connecting to \a host with options as \a callOptions. The channel may be new - * or a cached channel that is already connected. + * Create a channel with remote \a host and signature \a channelConfigurations. Destroy delay is + * defaulted to 30 seconds. */ -+ (nullable instancetype)channelWithHost:(nonnull NSString *)host - callOptions:(nullable GRPCCallOptions *)callOptions; +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration; /** - * Create a channel object with the signature \a config. + * Create a channel with remote \a host, signature \a channelConfigurations, and destroy delay of + * \a destroyDelay. */ -+ (nullable instancetype)createChannelWithConfiguration:(nonnull GRPCChannelConfiguration *)config; +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration + destroyDelay:(NSTimeInterval)destroyDelay NS_DESIGNATED_INITIALIZER; /** - * Get a grpc core call object from this channel. + * Create a grpc core call object from this channel. The channel's refcount is added by 1. If no + * call is created, NULL is returned, and if the reason is because the channel is already + * disconnected, \a disconnected is set to YES. When the returned call is unreffed, the caller is + * obligated to call \a unref method once. \a disconnected may be null. */ -- (nullable grpc_call *)unmanagedCallWithPath:(nonnull NSString *)path - completionQueue:(nonnull GRPCCompletionQueue *)queue - callOptions:(nonnull GRPCCallOptions *)callOptions; +- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path + completionQueue:(GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions + disconnected:(BOOL * _Nullable)disconnected; /** - * Increase the refcount of the channel. If the channel was timed to be destroyed, cancel the timer. + * Unref the channel when a call is done. It also decreases the channel's refcount. If the refcount + * of the channel decreases to 0, the channel is destroyed after the destroy delay. */ -- (void)ref; +- (void)unref; /** - * Decrease the refcount of the channel. If the refcount of the channel decrease to 0, the channel - * is destroyed after 30 seconds. + * Force the channel to be disconnected and destroyed. */ -- (void)unref; +- (void)disconnect; /** - * Force the channel to be disconnected and destroyed immediately. + * Return whether the channel is already disconnected. */ -- (void)disconnect; +@property(readonly) BOOL disconnected; -// TODO (mxyan): deprecate with GRPCCall:closeOpenConnections -+ (void)closeOpenConnections; @end + +NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 773f4261d7..298b6605d1 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -28,141 +28,222 @@ #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "version.h" +#import "../internal/GRPCCallOptions+Internal.h" #import #import /** When all calls of a channel are destroyed, destroy the channel after this much seconds. */ -NSTimeInterval kChannelDestroyDelay = 30; +NSTimeInterval kDefaultChannelDestroyDelay = 30; -/** Global instance of channel pool. */ -static GRPCChannelPool *gChannelPool; +@implementation GRPCChannelConfiguration -/** - * Time the channel destroy when the channel's calls are unreffed. If there's new call, reset the - * timer. - */ -@interface GRPCChannelRef : NSObject +- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { + NSAssert(host.length, @"Host must not be empty."); + NSAssert(callOptions, @"callOptions must not be empty."); + if ((self = [super init])) { + _host = [host copy]; + _callOptions = [callOptions copy]; + } + return self; +} -- (instancetype)initWithDestroyDelay:(NSTimeInterval)destroyDelay - destroyChannelCallback:(void (^)())destroyChannelCallback; +- (id)channelFactory { + NSError *error; + id factory; + GRPCTransportType type = _callOptions.transportType; + switch (type) { + case GRPCTransportTypeChttp2BoringSSL: + // TODO (mxyan): Remove when the API is deprecated +#ifdef GRPC_COMPILE_WITH_CRONET + if (![GRPCCall isUsingCronet]) { +#endif + factory = [GRPCSecureChannelFactory + factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates + privateKey:_callOptions.PEMPrivateKey + certChain:_callOptions.PEMCertChain + error:&error]; + if (factory == nil) { + NSLog(@"Error creating secure channel factory: %@", error); + } + return factory; +#ifdef GRPC_COMPILE_WITH_CRONET + } +#endif + // fallthrough + case GRPCTransportTypeCronet: + return [GRPCCronetChannelFactory sharedInstance]; + case GRPCTransportTypeInsecure: + return [GRPCInsecureChannelFactory sharedInstance]; + } +} -/** Add call ref count to the channel and maybe reset the timer. */ -- (void)refChannel; +- (NSDictionary *)channelArgs { + NSMutableDictionary *args = [NSMutableDictionary new]; -/** Reduce call ref count to the channel and maybe set the timer. */ -- (void)unrefChannel; + NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING; + NSString *userAgentPrefix = _callOptions.userAgentPrefix; + if (userAgentPrefix) { + args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = + [_callOptions.userAgentPrefix stringByAppendingFormat:@" %@", userAgent]; + } else { + args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent; + } -/** Disconnect the channel. Any further ref/unref are discarded. */ -- (void)disconnect; + NSString *hostNameOverride = _callOptions.hostNameOverride; + if (hostNameOverride) { + args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = hostNameOverride; + } -@end + if (_callOptions.responseSizeLimit) { + args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = + [NSNumber numberWithUnsignedInteger:_callOptions.responseSizeLimit]; + } -@implementation GRPCChannelRef { - NSTimeInterval _destroyDelay; - void (^_destroyChannelCallback)(); + if (_callOptions.compressionAlgorithm != GRPC_COMPRESS_NONE) { + args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = + [NSNumber numberWithInt:_callOptions.compressionAlgorithm]; + } - NSUInteger _refCount; - BOOL _disconnected; - dispatch_queue_t _dispatchQueue; + if (_callOptions.keepaliveInterval != 0) { + args[@GRPC_ARG_KEEPALIVE_TIME_MS] = + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveInterval * 1000)]; + args[@GRPC_ARG_KEEPALIVE_TIMEOUT_MS] = + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveTimeout * 1000)]; + } - /** - * Date and time when last timer is scheduled. If a firing timer's scheduled date is different - * from this, it is discarded. - */ - NSDate *_lastDispatch; -} + if (_callOptions.retryEnabled == NO) { + args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:_callOptions.retryEnabled]; + } -- (instancetype)initWithDestroyDelay:(NSTimeInterval)destroyDelay - destroyChannelCallback:(void (^)())destroyChannelCallback { - if ((self = [super init])) { - _destroyDelay = destroyDelay; - _destroyChannelCallback = destroyChannelCallback; + if (_callOptions.connectMinTimeout > 0) { + args[@GRPC_ARG_MIN_RECONNECT_BACKOFF_MS] = + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMinTimeout * 1000)]; + } + if (_callOptions.connectInitialBackoff > 0) { + args[@GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS] = [NSNumber + numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectInitialBackoff * 1000)]; + } + if (_callOptions.connectMaxBackoff > 0) { + args[@GRPC_ARG_MAX_RECONNECT_BACKOFF_MS] = + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMaxBackoff * 1000)]; + } - _refCount = 1; - _disconnected = NO; - if (@available(iOS 8.0, *)) { - _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); - } else { - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } - _lastDispatch = nil; + if (_callOptions.logContext != nil) { + args[@GRPC_ARG_MOBILE_LOG_CONTEXT] = _callOptions.logContext; } - return self; -} -- (void)refChannel { - dispatch_async(_dispatchQueue, ^{ - if (!self->_disconnected) { - self->_refCount++; - self->_lastDispatch = nil; - } - }); + if (_callOptions.channelPoolDomain.length != 0) { + args[@GRPC_ARG_CHANNEL_POOL_DOMAIN] = _callOptions.channelPoolDomain; + } + + [args addEntriesFromDictionary:_callOptions.additionalChannelArgs]; + + return args; } -- (void)unrefChannel { - dispatch_async(_dispatchQueue, ^{ - if (!self->_disconnected) { - self->_refCount--; - if (self->_refCount == 0) { - NSDate *now = [NSDate date]; - self->_lastDispatch = now; - dispatch_time_t delay = - dispatch_time(DISPATCH_TIME_NOW, (int64_t)self->_destroyDelay * NSEC_PER_SEC); - dispatch_after(delay, self->_dispatchQueue, ^{ - [self timedDisconnectWithScheduleDate:now]; - }); - } - } - }); +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + GRPCChannelConfiguration *newConfig = + [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; + + return newConfig; } -- (void)disconnect { - dispatch_async(_dispatchQueue, ^{ - if (!self->_disconnected) { - self->_lastDispatch = nil; - self->_disconnected = YES; - // Break retain loop - self->_destroyChannelCallback = nil; - } - }); +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[GRPCChannelConfiguration class]]) { + return NO; + } + GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; + if (!(obj.host == _host || (_host != nil && [obj.host isEqualToString:_host]))) return NO; + if (!(obj.callOptions == _callOptions || [obj.callOptions hasChannelOptionsEqualTo:_callOptions])) + return NO; + + return YES; } -- (void)timedDisconnectWithScheduleDate:(NSDate *)scheduleDate { - dispatch_async(_dispatchQueue, ^{ - if (self->_disconnected || self->_lastDispatch != scheduleDate) { - return; - } - self->_lastDispatch = nil; - self->_disconnected = YES; - self->_destroyChannelCallback(); - // Break retain loop - self->_destroyChannelCallback = nil; - }); +- (NSUInteger)hash { + NSUInteger result = 0; + result ^= _host.hash; + result ^= _callOptions.channelOptionsHash; + + return result; } @end + + @implementation GRPCChannel { GRPCChannelConfiguration *_configuration; - grpc_channel *_unmanagedChannel; - GRPCChannelRef *_channelRef; + dispatch_queue_t _dispatchQueue; + grpc_channel *_unmanagedChannel; + NSTimeInterval _destroyDelay; + + NSUInteger _refcount; + NSDate *_lastDispatch; +} +@synthesize disconnected = _disconnected; + +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { + return [self initWithChannelConfiguration:channelConfiguration + destroyDelay:kDefaultChannelDestroyDelay]; +} + +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration + destroyDelay:(NSTimeInterval)destroyDelay { + NSAssert(channelConfiguration, @"channelConfiguration must not be empty."); + NSAssert(destroyDelay > 0, @"destroyDelay must be greater than 0."); + if ((self = [super init])) { + _configuration = [channelConfiguration copy]; + if (@available(iOS 8.0, *)) { + _dispatchQueue = dispatch_queue_create( + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + } else { + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } + + // Create gRPC core channel object. + NSString *host = channelConfiguration.host; + NSAssert(host.length != 0, @"host cannot be nil"); + NSDictionary *channelArgs; + if (channelConfiguration.callOptions.additionalChannelArgs.count != 0) { + NSMutableDictionary *args = [channelConfiguration.channelArgs mutableCopy]; + [args addEntriesFromDictionary:channelConfiguration.callOptions.additionalChannelArgs]; + channelArgs = args; + } else { + channelArgs = channelConfiguration.channelArgs; + } + id factory = channelConfiguration.channelFactory; + _unmanagedChannel = [factory createChannelWithHost:host channelArgs:channelArgs]; + if (_unmanagedChannel == NULL) { + NSLog(@"Unable to create channel."); + return nil; + } + _destroyDelay = destroyDelay; + _disconnected = NO; + } + return self; } - (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue - callOptions:(GRPCCallOptions *)callOptions { + callOptions:(GRPCCallOptions *)callOptions + disconnected:(BOOL *)disconnected { NSAssert(path.length, @"path must not be empty."); NSAssert(queue, @"completionQueue must not be empty."); NSAssert(callOptions, @"callOptions must not be empty."); - __block grpc_call *call = nil; + __block BOOL isDisconnected = NO; + __block grpc_call *call = NULL; dispatch_sync(_dispatchQueue, ^{ - if (self->_unmanagedChannel) { + if (self->_disconnected) { + isDisconnected = YES; + } else { + NSAssert(self->_unmanagedChannel != NULL, @"Invalid channel."); + NSString *serverAuthority = - callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; + callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; NSAssert(timeout >= 0, @"Invalid timeout"); grpc_slice host_slice = grpc_empty_slice(); @@ -171,10 +252,10 @@ static GRPCChannelPool *gChannelPool; } grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); gpr_timespec deadline_ms = - timeout == 0 - ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + timeout == 0 + ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); call = grpc_channel_create_call(self->_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, serverAuthority ? &host_slice : NULL, deadline_ms, NULL); @@ -182,71 +263,64 @@ static GRPCChannelPool *gChannelPool; grpc_slice_unref(host_slice); } grpc_slice_unref(path_slice); - } else { - NSAssert(self->_unmanagedChannel != nil, @"Invalid channeg."); + if (call == NULL) { + NSLog(@"Unable to create call."); + } else { + // Ref the channel; + [self ref]; + } } }); + if (disconnected != nil) { + *disconnected = isDisconnected; + } return call; } +// This function should be called on _dispatchQueue. - (void)ref { - dispatch_async(_dispatchQueue, ^{ - if (self->_unmanagedChannel) { - [self->_channelRef refChannel]; - } - }); + _refcount++; + if (_refcount == 1 && _lastDispatch != nil) { + _lastDispatch = nil; + } } - (void)unref { dispatch_async(_dispatchQueue, ^{ - if (self->_unmanagedChannel) { - [self->_channelRef unrefChannel]; + self->_refcount--; + if (self->_refcount == 0 && !self->_disconnected) { + // Start timer. + dispatch_time_t delay = + dispatch_time(DISPATCH_TIME_NOW, (int64_t)self->_destroyDelay * NSEC_PER_SEC); + NSDate *now = [NSDate date]; + self->_lastDispatch = now; + dispatch_after(delay, self->_dispatchQueue, ^{ + if (self->_lastDispatch == now) { + grpc_channel_destroy(self->_unmanagedChannel); + self->_unmanagedChannel = NULL; + self->_disconnected = YES; + } + }); } }); } - (void)disconnect { dispatch_async(_dispatchQueue, ^{ - if (self->_unmanagedChannel) { + if (!self->_disconnected) { grpc_channel_destroy(self->_unmanagedChannel); self->_unmanagedChannel = nil; - [self->_channelRef disconnect]; + self->_disconnected = YES; } }); } -- (void)destroyChannel { - dispatch_async(_dispatchQueue, ^{ - if (self->_unmanagedChannel) { - grpc_channel_destroy(self->_unmanagedChannel); - self->_unmanagedChannel = nil; - [gChannelPool removeChannel:self]; - } +- (BOOL)disconnected { + __block BOOL disconnected; + dispatch_sync(_dispatchQueue, ^{ + disconnected = self->_disconnected; }); -} - -- (nullable instancetype)initWithUnmanagedChannel:(grpc_channel *_Nullable)unmanagedChannel - configuration:(GRPCChannelConfiguration *)configuration { - NSAssert(configuration, @"Configuration must not be empty."); - if (!unmanagedChannel) { - return nil; - } - if ((self = [super init])) { - _unmanagedChannel = unmanagedChannel; - _configuration = [configuration copy]; - _channelRef = [[GRPCChannelRef alloc] initWithDestroyDelay:kChannelDestroyDelay - destroyChannelCallback:^{ - [self destroyChannel]; - }]; - if (@available(iOS 8.0, *)) { - _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); - } else { - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } - } - return self; + return disconnected; } - (void)dealloc { @@ -255,47 +329,4 @@ static GRPCChannelPool *gChannelPool; } } -+ (nullable instancetype)createChannelWithConfiguration:(GRPCChannelConfiguration *)config { - NSAssert(config != nil, @"configuration cannot be empty"); - NSString *host = config.host; - NSAssert(host.length != 0, @"host cannot be nil"); - - NSDictionary *channelArgs; - if (config.callOptions.additionalChannelArgs.count != 0) { - NSMutableDictionary *args = [config.channelArgs mutableCopy]; - [args addEntriesFromDictionary:config.callOptions.additionalChannelArgs]; - channelArgs = args; - } else { - channelArgs = config.channelArgs; - } - id factory = config.channelFactory; - grpc_channel *unmanaged_channel = [factory createChannelWithHost:host channelArgs:channelArgs]; - return [[GRPCChannel alloc] initWithUnmanagedChannel:unmanaged_channel configuration:config]; -} - -+ (nullable instancetype)channelWithHost:(NSString *)host - callOptions:(GRPCCallOptions *)callOptions { - static dispatch_once_t initChannelPool; - dispatch_once(&initChannelPool, ^{ - gChannelPool = [[GRPCChannelPool alloc] init]; - }); - - NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:host]]; - if (hostURL.host && !hostURL.port) { - host = [hostURL.host stringByAppendingString:@":443"]; - } - - GRPCChannelConfiguration *channelConfig = - [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; - if (channelConfig == nil) { - return nil; - } - - return [gChannelPool channelWithConfiguration:channelConfig]; -} - -+ (void)closeOpenConnections { - [gChannelPool removeAndCloseAllChannels]; -} - @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index f99c0ba4dc..24c0a8df11 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -29,48 +29,45 @@ NS_ASSUME_NONNULL_BEGIN @class GRPCChannel; -/** Caching signature of a channel. */ -@interface GRPCChannelConfiguration : NSObject - -/** The host that this channel is connected to. */ -@property(copy, readonly) NSString *host; - -/** - * Options of the corresponding call. Note that only the channel-related options are of interest to - * this class. - */ -@property(strong, readonly) GRPCCallOptions *callOptions; - -/** Acquire the factory to generate a new channel with current configurations. */ -@property(readonly) id channelFactory; - -/** Acquire the dictionary of channel args with current configurations. */ -@property(copy, readonly) NSDictionary *channelArgs; - -- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; - -@end - /** * Manage the pool of connected channels. When a channel is no longer referenced by any call, * destroy the channel after a certain period of time elapsed. */ @interface GRPCChannelPool : NSObject +/** + * Get the singleton instance + */ ++ (nullable instancetype)sharedInstance; + /** * Return a channel with a particular configuration. If the channel does not exist, execute \a * createChannel then add it in the pool. If the channel exists, increase its reference count. */ -- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration; +- (GRPCChannel *)channelWithHost:(NSString *)host + callOptions:(GRPCCallOptions *)callOptions; + +/** + * This method is deprecated. + * + * Destroy all open channels and close their connections. + */ ++ (void)closeOpenConnections; -/** Remove a channel from the pool. */ -- (void)removeChannel:(GRPCChannel *)channel; +// Test-only methods below -/** Clear all channels in the pool. */ -- (void)removeAllChannels; +/** + * Return a channel with a special destroy delay. If \a destroyDelay is 0, use the default destroy + * delay. + */ +- (GRPCChannel *)channelWithHost:(NSString *)host + callOptions:(GRPCCallOptions *)callOptions + destroyDelay:(NSTimeInterval)destroyDelay; -/** Clear all channels in the pool and destroy the channels. */ -- (void)removeAndCloseAllChannels; +/** + * Simulate a network transition event and destroy all channels. + */ +- (void)destroyAllChannels; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 1bf2a5c563..98c1634bc8 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -33,147 +33,23 @@ extern const char *kCFStreamVarName; -@implementation GRPCChannelConfiguration - -- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { - NSAssert(host.length, @"Host must not be empty."); - NSAssert(callOptions, @"callOptions must not be empty."); - if ((self = [super init])) { - _host = [host copy]; - _callOptions = [callOptions copy]; - } - return self; -} - -- (id)channelFactory { - NSError *error; - id factory; - GRPCTransportType type = _callOptions.transportType; - switch (type) { - case GRPCTransportTypeChttp2BoringSSL: - // TODO (mxyan): Remove when the API is deprecated -#ifdef GRPC_COMPILE_WITH_CRONET - if (![GRPCCall isUsingCronet]) { -#endif - factory = [GRPCSecureChannelFactory - factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates - privateKey:_callOptions.PEMPrivateKey - certChain:_callOptions.PEMCertChain - error:&error]; - if (factory == nil) { - NSLog(@"Error creating secure channel factory: %@", error); - } - return factory; -#ifdef GRPC_COMPILE_WITH_CRONET - } -#endif - // fallthrough - case GRPCTransportTypeCronet: - return [GRPCCronetChannelFactory sharedInstance]; - case GRPCTransportTypeInsecure: - return [GRPCInsecureChannelFactory sharedInstance]; - } -} - -- (NSDictionary *)channelArgs { - NSMutableDictionary *args = [NSMutableDictionary new]; - - NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING; - NSString *userAgentPrefix = _callOptions.userAgentPrefix; - if (userAgentPrefix) { - args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = - [_callOptions.userAgentPrefix stringByAppendingFormat:@" %@", userAgent]; - } else { - args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent; - } - - NSString *hostNameOverride = _callOptions.hostNameOverride; - if (hostNameOverride) { - args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = hostNameOverride; - } - - if (_callOptions.responseSizeLimit) { - args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = - [NSNumber numberWithUnsignedInteger:_callOptions.responseSizeLimit]; - } - - if (_callOptions.compressionAlgorithm != GRPC_COMPRESS_NONE) { - args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = - [NSNumber numberWithInt:_callOptions.compressionAlgorithm]; - } - - if (_callOptions.keepaliveInterval != 0) { - args[@GRPC_ARG_KEEPALIVE_TIME_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveInterval * 1000)]; - args[@GRPC_ARG_KEEPALIVE_TIMEOUT_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveTimeout * 1000)]; - } - - if (_callOptions.retryEnabled == NO) { - args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:_callOptions.retryEnabled]; - } - - if (_callOptions.connectMinTimeout > 0) { - args[@GRPC_ARG_MIN_RECONNECT_BACKOFF_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMinTimeout * 1000)]; - } - if (_callOptions.connectInitialBackoff > 0) { - args[@GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS] = [NSNumber - numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectInitialBackoff * 1000)]; - } - if (_callOptions.connectMaxBackoff > 0) { - args[@GRPC_ARG_MAX_RECONNECT_BACKOFF_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMaxBackoff * 1000)]; - } - - if (_callOptions.logContext != nil) { - args[@GRPC_ARG_MOBILE_LOG_CONTEXT] = _callOptions.logContext; - } - - if (_callOptions.channelPoolDomain.length != 0) { - args[@GRPC_ARG_CHANNEL_POOL_DOMAIN] = _callOptions.channelPoolDomain; - } - - [args addEntriesFromDictionary:_callOptions.additionalChannelArgs]; - - return args; -} - -- (nonnull id)copyWithZone:(nullable NSZone *)zone { - GRPCChannelConfiguration *newConfig = - [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; - - return newConfig; -} - -- (BOOL)isEqual:(id)object { - if (![object isKindOfClass:[GRPCChannelConfiguration class]]) { - return NO; - } - GRPCChannelConfiguration *obj = (GRPCChannelConfiguration *)object; - if (!(obj.host == _host || (_host != nil && [obj.host isEqualToString:_host]))) return NO; - if (!(obj.callOptions == _callOptions || [obj.callOptions hasChannelOptionsEqualTo:_callOptions])) - return NO; - - return YES; -} - -- (NSUInteger)hash { - NSUInteger result = 0; - result ^= _host.hash; - result ^= _callOptions.channelOptionsHash; - - return result; -} - -@end - -#pragma mark GRPCChannelPool +static GRPCChannelPool *gChannelPool; +static dispatch_once_t gInitChannelPool; @implementation GRPCChannelPool { NSMutableDictionary *_channelPool; } ++ (nullable instancetype)sharedInstance { + dispatch_once(&gInitChannelPool, ^{ + gChannelPool = [[GRPCChannelPool alloc] init]; + if (gChannelPool == nil) { + [NSException raise:NSMallocException format:@"Cannot initialize global channel pool."]; + } + }); + return gChannelPool; +} + - (instancetype)init { if ((self = [super init])) { _channelPool = [NSMutableDictionary dictionary]; @@ -187,61 +63,56 @@ extern const char *kCFStreamVarName; return self; } -- (void)dealloc { - [GRPCConnectivityMonitor unregisterObserver:self]; +- (GRPCChannel *)channelWithHost:(NSString *)host + callOptions:(GRPCCallOptions *)callOptions { + return [self channelWithHost:host + callOptions:callOptions + destroyDelay:0]; } -- (GRPCChannel *)channelWithConfiguration:(GRPCChannelConfiguration *)configuration { - NSAssert(configuration != nil, @"Must has a configuration"); +- (GRPCChannel *)channelWithHost:(NSString *)host + callOptions:(GRPCCallOptions *)callOptions + destroyDelay:(NSTimeInterval)destroyDelay { + NSAssert(host.length > 0, @"Host must not be empty."); + NSAssert(callOptions != nil, @"callOptions must not be empty."); GRPCChannel *channel; + GRPCChannelConfiguration *configuration = + [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; @synchronized(self) { - if ([_channelPool objectForKey:configuration]) { - channel = _channelPool[configuration]; - [channel ref]; - } else { - channel = [GRPCChannel createChannelWithConfiguration:configuration]; - if (channel != nil) { - _channelPool[configuration] = channel; + channel = _channelPool[configuration]; + if (channel == nil || channel.disconnected) { + if (destroyDelay == 0) { + channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration]; + } else { + channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration destroyDelay:destroyDelay]; } + _channelPool[configuration] = channel; } } return channel; } -- (void)removeChannel:(GRPCChannel *)channel { - @synchronized(self) { - __block GRPCChannelConfiguration *keyToDelete = nil; - [_channelPool - enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration *_Nonnull key, - GRPCChannel *_Nonnull obj, BOOL *_Nonnull stop) { - if (obj == channel) { - keyToDelete = key; - *stop = YES; - } - }]; - [self->_channelPool removeObjectForKey:keyToDelete]; - } -} -- (void)removeAllChannels { - @synchronized(self) { - _channelPool = [NSMutableDictionary dictionary]; - } + ++ (void)closeOpenConnections { + [[GRPCChannelPool sharedInstance] destroyAllChannels]; } -- (void)removeAndCloseAllChannels { +- (void)destroyAllChannels { @synchronized(self) { - [_channelPool - enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration *_Nonnull key, - GRPCChannel *_Nonnull obj, BOOL *_Nonnull stop) { - [obj disconnect]; - }]; + for (id key in _channelPool) { + [_channelPool[key] disconnect]; + } _channelPool = [NSMutableDictionary dictionary]; } } - (void)connectivityChange:(NSNotification *)note { - [self removeAndCloseAllChannels]; + [self destroyAllChannels]; +} + +- (void)dealloc { + [GRPCConnectivityMonitor unregisterObserver:self]; } @end diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 577002e7a8..2358c7bb0a 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -24,6 +24,7 @@ #include #import "GRPCChannel.h" +#import "GRPCChannelPool.h" #import "GRPCCompletionQueue.h" #import "GRPCHost.h" #import "NSData+GRPC.h" @@ -256,13 +257,21 @@ // consuming too many threads and having contention of multiple calls in a single completion // queue. Currently we use a singleton queue. _queue = [GRPCCompletionQueue completionQueue]; - _channel = [GRPCChannel channelWithHost:host callOptions:callOptions]; - if (_channel == nil) { - NSLog(@"Failed to get a channel for the host."); - return nil; - } - _call = [_channel unmanagedCallWithPath:path completionQueue:_queue callOptions:callOptions]; - if (_call == NULL) { + BOOL disconnected; + do { + _channel = [[GRPCChannelPool sharedInstance] channelWithHost:host callOptions:callOptions]; + if (_channel == nil) { + NSLog(@"Failed to get a channel for the host."); + return nil; + } + _call = [_channel unmanagedCallWithPath:path + completionQueue:_queue + callOptions:callOptions + disconnected:&disconnected]; + // Try create another channel if the current channel is disconnected (due to idleness or + // connectivity monitor disconnection). + } while (_call == NULL && disconnected); + if (_call == nil) { NSLog(@"Failed to create a call."); return nil; } @@ -317,6 +326,7 @@ - (void)dealloc { if (_call) { grpc_call_unref(_call); + [_channel unref]; } [_channel unref]; _channel = nil; diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index 5c3f0edba0..d684db545e 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -20,6 +20,7 @@ #import "../../GRPCClient/private/GRPCChannel.h" #import "../../GRPCClient/private/GRPCChannelPool.h" +#import "../../GRPCClient/private/GRPCCompletionQueue.h" #define TEST_TIMEOUT 32 @@ -35,92 +36,104 @@ NSString *kDummyHost = @"dummy.host"; grpc_init(); } -- (void)testCreateChannel { +- (void)testChannelPooling { NSString *kDummyHost = @"dummy.host"; + NSString *kDummyHost2 = @"dummy.host2"; + GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; - options1.transportType = GRPCTransportTypeInsecure; GRPCCallOptions *options2 = [options1 copy]; - GRPCChannelConfiguration *config1 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; - GRPCChannelConfiguration *config2 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - - GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; - GRPCChannel *channel2 = [pool channelWithConfiguration:config2]; + GRPCMutableCallOptions *options3 = [options2 mutableCopy]; + options3.transportType = GRPCTransportTypeInsecure; + + GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; + + GRPCChannel *channel1 = [pool channelWithHost:kDummyHost + callOptions:options1]; + GRPCChannel *channel2 = [pool channelWithHost:kDummyHost + callOptions:options2]; + GRPCChannel *channel3 = [pool channelWithHost:kDummyHost2 + callOptions:options1]; + GRPCChannel *channel4 = [pool channelWithHost:kDummyHost + callOptions:options3]; XCTAssertEqual(channel1, channel2); + XCTAssertNotEqual(channel1, channel3); + XCTAssertNotEqual(channel1, channel4); + XCTAssertNotEqual(channel3, channel4); } -- (void)testChannelRemove { - GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; - options1.transportType = GRPCTransportTypeInsecure; - GRPCChannelConfiguration *config1 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; - [pool removeChannel:channel1]; - GRPCChannel *channel2 = [pool channelWithConfiguration:config1]; - XCTAssertNotEqual(channel1, channel2); -} - -extern NSTimeInterval kChannelDestroyDelay; +- (void)testDestroyAllChannels { + NSString *kDummyHost = @"dummy.host"; -- (void)testChannelTimeoutCancel { - NSTimeInterval kOriginalInterval = kChannelDestroyDelay; - kChannelDestroyDelay = 3.0; - GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; - options1.transportType = GRPCTransportTypeInsecure; - GRPCChannelConfiguration *config1 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; - [channel1 unref]; - sleep(1); - GRPCChannel *channel2 = [pool channelWithConfiguration:config1]; - XCTAssertEqual(channel1, channel2); - sleep((int)kChannelDestroyDelay + 2); - GRPCChannel *channel3 = [pool channelWithConfiguration:config1]; - XCTAssertEqual(channel1, channel3); - kChannelDestroyDelay = kOriginalInterval; + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; + GRPCChannel *channel = [pool channelWithHost:kDummyHost + callOptions:options]; + grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:options + disconnected:nil]; + [pool destroyAllChannels]; + XCTAssertTrue(channel.disconnected); + GRPCChannel *channel2 = [pool channelWithHost:kDummyHost + callOptions:options]; + XCTAssertNotEqual(channel, channel2); + grpc_call_unref(call); } -- (void)testChannelDisconnect { +- (void)testGetChannelBeforeChannelTimedDisconnection { NSString *kDummyHost = @"dummy.host"; - GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; - options1.transportType = GRPCTransportTypeInsecure; - GRPCCallOptions *options2 = [options1 copy]; - GRPCChannelConfiguration *config1 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; - GRPCChannelConfiguration *config2 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - - GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; - [pool removeAndCloseAllChannels]; - GRPCChannel *channel2 = [pool channelWithConfiguration:config2]; - XCTAssertNotEqual(channel1, channel2); + const NSTimeInterval kDestroyDelay = 1; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; + GRPCChannel *channel = [pool channelWithHost:kDummyHost + callOptions:options + destroyDelay:kDestroyDelay]; + grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:options + disconnected:nil]; + grpc_call_unref(call); + [channel unref]; + + // Test that we can still get the channel at this time + GRPCChannel *channel2 = [pool channelWithHost:kDummyHost + callOptions:options + destroyDelay:kDestroyDelay]; + XCTAssertEqual(channel, channel2); + call = [channel2 unmanagedCallWithPath:@"dummy.path" + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:options + disconnected:nil]; + + // Test that after the destroy delay, the channel is still alive + sleep(kDestroyDelay + 1); + XCTAssertFalse(channel.disconnected); } -- (void)testClearChannels { - GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; - options1.transportType = GRPCTransportTypeInsecure; - GRPCMutableCallOptions *options2 = [[GRPCMutableCallOptions alloc] init]; - options2.transportType = GRPCTransportTypeChttp2BoringSSL; - GRPCChannelConfiguration *config1 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1]; - GRPCChannelConfiguration *config2 = - [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2]; - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - - GRPCChannel *channel1 = [pool channelWithConfiguration:config1]; - GRPCChannel *channel2 = [pool channelWithConfiguration:config2]; - XCTAssertNotEqual(channel1, channel2); - - [pool removeAndCloseAllChannels]; - GRPCChannel *channel3 = [pool channelWithConfiguration:config1]; - GRPCChannel *channel4 = [pool channelWithConfiguration:config2]; - XCTAssertNotEqual(channel1, channel3); - XCTAssertNotEqual(channel2, channel4); +- (void)testGetChannelAfterChannelTimedDisconnection { + NSString *kDummyHost = @"dummy.host"; + const NSTimeInterval kDestroyDelay = 1; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; + GRPCChannel *channel = [pool channelWithHost:kDummyHost + callOptions:options + destroyDelay:kDestroyDelay]; + grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:options + disconnected:nil]; + grpc_call_unref(call); + [channel unref]; + + sleep(kDestroyDelay + 1); + + // Test that we get new channel to the same host and with the same callOptions + GRPCChannel *channel2 = [pool channelWithHost:kDummyHost + callOptions:options + destroyDelay:kDestroyDelay]; + XCTAssertNotEqual(channel, channel2); } @end diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index 64c3356b13..27e76d4179 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -20,6 +20,7 @@ #import "../../GRPCClient/GRPCCallOptions.h" #import "../../GRPCClient/private/GRPCChannel.h" +#import "../../GRPCClient/private/GRPCCompletionQueue.h" @interface ChannelTests : XCTestCase @@ -31,63 +32,51 @@ grpc_init(); } -- (void)testSameConfiguration { - NSString *host = @"grpc-test.sandbox.googleapis.com"; - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.userAgentPrefix = @"TestUAPrefix"; - NSMutableDictionary *args = [NSMutableDictionary new]; - args[@"abc"] = @"xyz"; - options.additionalChannelArgs = [args copy]; - GRPCChannel *channel1 = [GRPCChannel channelWithHost:host callOptions:options]; - GRPCChannel *channel2 = [GRPCChannel channelWithHost:host callOptions:options]; - XCTAssertEqual(channel1, channel2); - GRPCMutableCallOptions *options2 = [options mutableCopy]; - options2.additionalChannelArgs = [args copy]; - GRPCChannel *channel3 = [GRPCChannel channelWithHost:host callOptions:options2]; - XCTAssertEqual(channel1, channel3); -} +- (void)testTimedDisconnection { + NSString * const kHost = @"grpc-test.sandbox.googleapis.com"; + const NSTimeInterval kDestroyDelay = 1; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; + GRPCChannel *channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration + destroyDelay:kDestroyDelay]; + BOOL disconnected; + grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:options + disconnected:&disconnected]; + XCTAssertFalse(disconnected); + grpc_call_unref(call); + [channel unref]; + XCTAssertFalse(channel.disconnected, @"Channel is pre-maturely disconnected."); + sleep(kDestroyDelay + 1); + XCTAssertTrue(channel.disconnected, @"Channel is not disconnected after delay."); -- (void)testDifferentHost { - NSString *host1 = @"grpc-test.sandbox.googleapis.com"; - NSString *host2 = @"grpc-test2.sandbox.googleapis.com"; - NSString *host3 = @"http://grpc-test.sandbox.googleapis.com"; - NSString *host4 = @"dns://grpc-test.sandbox.googleapis.com"; - NSString *host5 = @"grpc-test.sandbox.googleapis.com:80"; - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.userAgentPrefix = @"TestUAPrefix"; - NSMutableDictionary *args = [NSMutableDictionary new]; - args[@"abc"] = @"xyz"; - options.additionalChannelArgs = [args copy]; - GRPCChannel *channel1 = [GRPCChannel channelWithHost:host1 callOptions:options]; - GRPCChannel *channel2 = [GRPCChannel channelWithHost:host2 callOptions:options]; - GRPCChannel *channel3 = [GRPCChannel channelWithHost:host3 callOptions:options]; - GRPCChannel *channel4 = [GRPCChannel channelWithHost:host4 callOptions:options]; - GRPCChannel *channel5 = [GRPCChannel channelWithHost:host5 callOptions:options]; - XCTAssertNotEqual(channel1, channel2); - XCTAssertNotEqual(channel1, channel3); - XCTAssertNotEqual(channel1, channel4); - XCTAssertNotEqual(channel1, channel5); + // Check another call creation returns null and indicates disconnected. + call = [channel unmanagedCallWithPath:@"dummy.path" + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:options + disconnected:&disconnected]; + XCTAssert(call == NULL); + XCTAssertTrue(disconnected); } -- (void)testDifferentChannelParameters { - NSString *host = @"grpc-test.sandbox.googleapis.com"; - GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; - options1.transportType = GRPCTransportTypeChttp2BoringSSL; - NSMutableDictionary *args = [NSMutableDictionary new]; - args[@"abc"] = @"xyz"; - options1.additionalChannelArgs = [args copy]; - GRPCMutableCallOptions *options2 = [[GRPCMutableCallOptions alloc] init]; - options2.transportType = GRPCTransportTypeInsecure; - options2.additionalChannelArgs = [args copy]; - GRPCMutableCallOptions *options3 = [[GRPCMutableCallOptions alloc] init]; - options3.transportType = GRPCTransportTypeChttp2BoringSSL; - args[@"def"] = @"uvw"; - options3.additionalChannelArgs = [args copy]; - GRPCChannel *channel1 = [GRPCChannel channelWithHost:host callOptions:options1]; - GRPCChannel *channel2 = [GRPCChannel channelWithHost:host callOptions:options2]; - GRPCChannel *channel3 = [GRPCChannel channelWithHost:host callOptions:options3]; - XCTAssertNotEqual(channel1, channel2); - XCTAssertNotEqual(channel1, channel3); +- (void)testForceDisconnection { + NSString * const kHost = @"grpc-test.sandbox.googleapis.com"; + const NSTimeInterval kDestroyDelay = 1; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; + GRPCChannel *channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration + destroyDelay:kDestroyDelay]; + grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:options + disconnected:nil]; + grpc_call_unref(call); + [channel disconnect]; + XCTAssertTrue(channel.disconnected, @"Channel is not disconnected."); + + // Test calling another unref here will not crash + [channel unref]; } @end -- cgit v1.2.3 From 861e7ce452866311ee2746d7b7a9fd1d11b84087 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 9 Nov 2018 07:51:38 -0800 Subject: nit fixes --- src/objective-c/GRPCClient/private/GRPCChannel.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 298b6605d1..4f26b349b4 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -34,7 +34,7 @@ #import /** When all calls of a channel are destroyed, destroy the channel after this much seconds. */ -NSTimeInterval kDefaultChannelDestroyDelay = 30; +static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @implementation GRPCChannelConfiguration @@ -295,6 +295,7 @@ NSTimeInterval kDefaultChannelDestroyDelay = 30; NSDate *now = [NSDate date]; self->_lastDispatch = now; dispatch_after(delay, self->_dispatchQueue, ^{ + // Timed disconnection. if (self->_lastDispatch == now) { grpc_channel_destroy(self->_unmanagedChannel); self->_unmanagedChannel = NULL; -- cgit v1.2.3 From 33022c9172bd3cf52c9aa3416ce9c69d9f3c6494 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 9 Nov 2018 10:23:05 -0800 Subject: Introduce GRPCAssert --- src/objective-c/GRPCClient/GRPCCall.m | 47 ++++++++-------------- src/objective-c/GRPCClient/private/GRPCChannel.m | 21 +++++----- .../GRPCClient/private/GRPCChannelPool.m | 9 ++--- src/objective-c/GRPCClient/private/GRPCHost.m | 3 +- .../GRPCClient/private/GRPCSecureChannelFactory.m | 4 +- src/objective-c/GRPCClient/private/utilities.h | 35 ++++++++++++++++ 6 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 src/objective-c/GRPCClient/private/utilities.h diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 9b9b4f9547..3d06aa929b 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -35,6 +35,7 @@ #import "private/NSData+GRPC.h" #import "private/NSDictionary+GRPC.h" #import "private/NSError+GRPC.h" +#import "private/utilities.h" // At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA, // SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE, @@ -67,7 +68,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; @implementation GRPCRequestOptions - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { - NSAssert(host.length != 0 && path.length != 0, @"Host and Path cannot be empty"); + GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, @"Host and Path cannot be empty"); if ((self = [super init])) { _host = [host copy]; _path = [path copy]; @@ -114,15 +115,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler callOptions:(GRPCCallOptions *_Nullable)callOptions { - if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { - [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; - } - if (requestOptions.safety > GRPCCallSafetyCacheableRequest) { - [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; - } - if (responseHandler == nil) { - [NSException raise:NSInvalidArgumentException format:@"Response handler required."]; - } + GRPCAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0, NSInvalidArgumentException, @"Neither host nor path can be nil."); + GRPCAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, @"Invalid call safety value."); + GRPCAssert(responseHandler != nil, NSInvalidArgumentException, @"Response handler required."); if ((self = [super init])) { _requestOptions = [requestOptions copy]; @@ -159,8 +154,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)start { dispatch_async(_dispatchQueue, ^{ - NSAssert(!self->_started, @"Call already started."); - NSAssert(!self->_canceled, @"Call already canceled."); + GRPCAssert(!self->_started, NSInternalInconsistencyException, @"Call already started."); + GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call already canceled."); self->_started = YES; if (!self->_callOptions) { self->_callOptions = [[GRPCCallOptions alloc] init]; @@ -216,7 +211,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancel { dispatch_async(_dispatchQueue, ^{ - NSAssert(!self->_canceled, @"Call already canceled."); + GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call already canceled."); if (self->_call) { [self->_call cancel]; self->_call = nil; @@ -244,8 +239,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)writeData:(NSData *)data { dispatch_async(_dispatchQueue, ^{ - NSAssert(!self->_canceled, @"Call arleady canceled."); - NSAssert(!self->_finished, @"Call is half-closed before sending data."); + GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call arleady canceled."); + GRPCAssert(!self->_finished, NSInternalInconsistencyException, @"Call is half-closed before sending data."); if (self->_call) { [self->_pipe writeValue:data]; } @@ -254,9 +249,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)finish { dispatch_async(_dispatchQueue, ^{ - NSAssert(self->_started, @"Call not started."); - NSAssert(!self->_canceled, @"Call arleady canceled."); - NSAssert(!self->_finished, @"Call already half-closed."); + GRPCAssert(self->_started, NSInternalInconsistencyException, @"Call not started."); + GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call arleady canceled."); + GRPCAssert(!self->_finished, NSInternalInconsistencyException, @"Call already half-closed."); if (self->_call) { [self->_pipe writesFinishedWithError:nil]; } @@ -404,16 +399,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. - if (!host || !path) { - [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; - } - if (safety > GRPCCallSafetyCacheableRequest) { - [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; - } - if (requestWriter.state != GRXWriterStateNotStarted) { - [NSException raise:NSInvalidArgumentException - format:@"The requests writer can't be already started."]; - } + GRPCAssert(host && path, NSInvalidArgumentException, @"Neither host nor path can be nil."); + GRPCAssert(safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, @"Invalid call safety value."); + GRPCAssert(requestWriter.state == GRXWriterStateNotStarted, NSInvalidArgumentException, @"The requests writer can't be already started."); if ((self = [super init])) { _host = [host copy]; _path = [path copy]; @@ -798,8 +786,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; _callOptions = callOptions; } - NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, - @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); + GRPCAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, NSInvalidArgumentException, @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); if (_callOptions.authTokenProvider != nil) { @synchronized(self) { self.isWaitingForToken = YES; diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 4f26b349b4..7d0baa91ee 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -28,6 +28,7 @@ #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "version.h" +#import "utilities.h" #import "../internal/GRPCCallOptions+Internal.h" #import @@ -39,8 +40,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @implementation GRPCChannelConfiguration - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { - NSAssert(host.length, @"Host must not be empty."); - NSAssert(callOptions, @"callOptions must not be empty."); + GRPCAssert(host.length, NSInvalidArgumentException, @"Host must not be empty."); + GRPCAssert(callOptions != nil, NSInvalidArgumentException, @"callOptions must not be empty."); if ((self = [super init])) { _host = [host copy]; _callOptions = [callOptions copy]; @@ -192,8 +193,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration destroyDelay:(NSTimeInterval)destroyDelay { - NSAssert(channelConfiguration, @"channelConfiguration must not be empty."); - NSAssert(destroyDelay > 0, @"destroyDelay must be greater than 0."); + GRPCAssert(channelConfiguration != nil, NSInvalidArgumentException, @"channelConfiguration must not be empty."); + GRPCAssert(destroyDelay > 0, NSInvalidArgumentException, @"destroyDelay must be greater than 0."); if ((self = [super init])) { _configuration = [channelConfiguration copy]; if (@available(iOS 8.0, *)) { @@ -206,7 +207,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; // Create gRPC core channel object. NSString *host = channelConfiguration.host; - NSAssert(host.length != 0, @"host cannot be nil"); + GRPCAssert(host.length != 0, NSInvalidArgumentException, @"host cannot be nil"); NSDictionary *channelArgs; if (channelConfiguration.callOptions.additionalChannelArgs.count != 0) { NSMutableDictionary *args = [channelConfiguration.channelArgs mutableCopy]; @@ -231,21 +232,21 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions disconnected:(BOOL *)disconnected { - NSAssert(path.length, @"path must not be empty."); - NSAssert(queue, @"completionQueue must not be empty."); - NSAssert(callOptions, @"callOptions must not be empty."); + GRPCAssert(path.length, NSInvalidArgumentException, @"path must not be empty."); + GRPCAssert(queue, NSInvalidArgumentException, @"completionQueue must not be empty."); + GRPCAssert(callOptions, NSInvalidArgumentException, @"callOptions must not be empty."); __block BOOL isDisconnected = NO; __block grpc_call *call = NULL; dispatch_sync(_dispatchQueue, ^{ if (self->_disconnected) { isDisconnected = YES; } else { - NSAssert(self->_unmanagedChannel != NULL, @"Invalid channel."); + GRPCAssert(self->_unmanagedChannel != NULL, NSInvalidArgumentException, @"Invalid channel."); NSString *serverAuthority = callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; - NSAssert(timeout >= 0, @"Invalid timeout"); + GRPCAssert(timeout >= 0, NSInvalidArgumentException, @"Invalid timeout"); grpc_slice host_slice = grpc_empty_slice(); if (serverAuthority) { host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 98c1634bc8..8a3b5edfa1 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -27,6 +27,7 @@ #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "version.h" +#import "utilities.h" #import #include @@ -43,9 +44,7 @@ static dispatch_once_t gInitChannelPool; + (nullable instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ gChannelPool = [[GRPCChannelPool alloc] init]; - if (gChannelPool == nil) { - [NSException raise:NSMallocException format:@"Cannot initialize global channel pool."]; - } + GRPCAssert(gChannelPool != nil, NSMallocException, @"Cannot initialize global channel pool."); }); return gChannelPool; } @@ -73,8 +72,8 @@ static dispatch_once_t gInitChannelPool; - (GRPCChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions destroyDelay:(NSTimeInterval)destroyDelay { - NSAssert(host.length > 0, @"Host must not be empty."); - NSAssert(callOptions != nil, @"callOptions must not be empty."); + GRPCAssert(host.length > 0, NSInvalidArgumentException, @"Host must not be empty."); + GRPCAssert(callOptions != nil, NSInvalidArgumentException, @"callOptions must not be empty."); GRPCChannel *channel; GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index a67162c101..14d07e949b 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -33,6 +33,7 @@ #import "GRPCSecureChannelFactory.h" #import "NSDictionary+GRPC.h" #import "version.h" +#import "utilities.h" NS_ASSUME_NONNULL_BEGIN @@ -121,7 +122,7 @@ static NSMutableDictionary *gHostCache; if (_transportType == GRPCTransportTypeInsecure) { options.transportType = GRPCTransportTypeInsecure; } else { - NSAssert(_transportType == GRPCTransportTypeDefault, @"Invalid transport type"); + GRPCAssert(_transportType == GRPCTransportTypeDefault, NSInvalidArgumentException, @"Invalid transport type"); options.transportType = GRPCTransportTypeCronet; } } else diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 1f6458c524..3079394ed8 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -22,6 +22,7 @@ #import "ChannelArgsUtil.h" #import "GRPCChannel.h" +#import "utilities.h" NS_ASSUME_NONNULL_BEGIN @@ -82,8 +83,9 @@ NS_ASSUME_NONNULL_BEGIN if (errorPtr) { *errorPtr = defaultRootsError; } - NSAssert( + GRPCAssertWithArgument( defaultRootsASCII, + NSObjectNotAvailableException, @"Could not read gRPCCertificates.bundle/roots.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 " diff --git a/src/objective-c/GRPCClient/private/utilities.h b/src/objective-c/GRPCClient/private/utilities.h new file mode 100644 index 0000000000..c664e8bf9d --- /dev/null +++ b/src/objective-c/GRPCClient/private/utilities.h @@ -0,0 +1,35 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +/** Raise exception when condition not met. Disregard NS_BLOCK_ASSERTIONS. */ +#define GRPCAssert(condition, errorType, errorString) \ +do { \ +if (!(condition)) { \ +[NSException raise:(errorType) format:(errorString)]; \ +} \ +} while (0) + +/** The same as GRPCAssert but allows arguments to be put in the raised string. */ +#define GRPCAssertWithArgument(condition, errorType, errorFormat, ...) \ + do { \ + if (!(condition)) { \ + [NSException raise:(errorType) format:(errorFormat), __VA_ARGS__]; \ + } \ + } while (0) -- cgit v1.2.3 From 2895ee9b6a63c19ebbd6c188ab475f0a6e7f0ba5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 9 Nov 2018 11:06:46 -0800 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.m | 22 ++++++--- src/objective-c/GRPCClient/private/GRPCChannel.h | 11 +++-- src/objective-c/GRPCClient/private/GRPCChannel.m | 55 +++++++++++----------- .../GRPCClient/private/GRPCChannelPool.h | 3 +- .../GRPCClient/private/GRPCChannelPool.m | 16 +++---- src/objective-c/GRPCClient/private/GRPCHost.m | 5 +- .../GRPCClient/private/GRPCSecureChannelFactory.m | 3 +- src/objective-c/GRPCClient/private/utilities.h | 27 ++++++----- 8 files changed, 75 insertions(+), 67 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 3d06aa929b..5e3491dafa 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -68,7 +68,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; @implementation GRPCRequestOptions - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { - GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, @"Host and Path cannot be empty"); + GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, + @"Host and Path cannot be empty"); if ((self = [super init])) { _host = [host copy]; _path = [path copy]; @@ -115,8 +116,10 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler callOptions:(GRPCCallOptions *_Nullable)callOptions { - GRPCAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0, NSInvalidArgumentException, @"Neither host nor path can be nil."); - GRPCAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, @"Invalid call safety value."); + GRPCAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0, + NSInvalidArgumentException, @"Neither host nor path can be nil."); + GRPCAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, + @"Invalid call safety value."); GRPCAssert(responseHandler != nil, NSInvalidArgumentException, @"Response handler required."); if ((self = [super init])) { @@ -240,7 +243,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)writeData:(NSData *)data { dispatch_async(_dispatchQueue, ^{ GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call arleady canceled."); - GRPCAssert(!self->_finished, NSInternalInconsistencyException, @"Call is half-closed before sending data."); + GRPCAssert(!self->_finished, NSInternalInconsistencyException, + @"Call is half-closed before sending data."); if (self->_call) { [self->_pipe writeValue:data]; } @@ -400,8 +404,10 @@ const char *kCFStreamVarName = "grpc_cfstream"; callOptions:(GRPCCallOptions *)callOptions { // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. GRPCAssert(host && path, NSInvalidArgumentException, @"Neither host nor path can be nil."); - GRPCAssert(safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, @"Invalid call safety value."); - GRPCAssert(requestWriter.state == GRXWriterStateNotStarted, NSInvalidArgumentException, @"The requests writer can't be already started."); + GRPCAssert(safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, + @"Invalid call safety value."); + GRPCAssert(requestWriter.state == GRXWriterStateNotStarted, NSInvalidArgumentException, + @"The requests writer can't be already started."); if ((self = [super init])) { _host = [host copy]; _path = [path copy]; @@ -786,7 +792,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; _callOptions = callOptions; } - GRPCAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, NSInvalidArgumentException, @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); + GRPCAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, + NSInvalidArgumentException, + @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); if (_callOptions.authTokenProvider != nil) { @synchronized(self) { self.isWaitingForToken = YES; diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index bbe0ba5390..6c58f4f387 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -64,14 +64,17 @@ NS_ASSUME_NONNULL_BEGIN * Create a channel with remote \a host and signature \a channelConfigurations. Destroy delay is * defaulted to 30 seconds. */ -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration; +- (nullable instancetype)initWithChannelConfiguration: + (GRPCChannelConfiguration *)channelConfiguration; /** * Create a channel with remote \a host, signature \a channelConfigurations, and destroy delay of * \a destroyDelay. */ -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration - destroyDelay:(NSTimeInterval)destroyDelay NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithChannelConfiguration: + (GRPCChannelConfiguration *)channelConfiguration + destroyDelay:(NSTimeInterval)destroyDelay + NS_DESIGNATED_INITIALIZER; /** * Create a grpc core call object from this channel. The channel's refcount is added by 1. If no @@ -82,7 +85,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions - disconnected:(BOOL * _Nullable)disconnected; + disconnected:(BOOL *_Nullable)disconnected; /** * Unref the channel when a call is done. It also decreases the channel's refcount. If the refcount diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 7d0baa91ee..fc0448bb96 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -20,6 +20,7 @@ #include +#import "../internal/GRPCCallOptions+Internal.h" #import "ChannelArgsUtil.h" #import "GRPCChannelFactory.h" #import "GRPCChannelPool.h" @@ -27,9 +28,8 @@ #import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" -#import "version.h" #import "utilities.h" -#import "../internal/GRPCCallOptions+Internal.h" +#import "version.h" #import #import @@ -60,10 +60,10 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if (![GRPCCall isUsingCronet]) { #endif factory = [GRPCSecureChannelFactory - factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates - privateKey:_callOptions.PEMPrivateKey - certChain:_callOptions.PEMCertChain - error:&error]; + factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates + privateKey:_callOptions.PEMPrivateKey + certChain:_callOptions.PEMCertChain + error:&error]; if (factory == nil) { NSLog(@"Error creating secure channel factory: %@", error); } @@ -86,7 +86,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; NSString *userAgentPrefix = _callOptions.userAgentPrefix; if (userAgentPrefix) { args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = - [_callOptions.userAgentPrefix stringByAppendingFormat:@" %@", userAgent]; + [_callOptions.userAgentPrefix stringByAppendingFormat:@" %@", userAgent]; } else { args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent; } @@ -98,19 +98,19 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if (_callOptions.responseSizeLimit) { args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = - [NSNumber numberWithUnsignedInteger:_callOptions.responseSizeLimit]; + [NSNumber numberWithUnsignedInteger:_callOptions.responseSizeLimit]; } if (_callOptions.compressionAlgorithm != GRPC_COMPRESS_NONE) { args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = - [NSNumber numberWithInt:_callOptions.compressionAlgorithm]; + [NSNumber numberWithInt:_callOptions.compressionAlgorithm]; } if (_callOptions.keepaliveInterval != 0) { args[@GRPC_ARG_KEEPALIVE_TIME_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveInterval * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveInterval * 1000)]; args[@GRPC_ARG_KEEPALIVE_TIMEOUT_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveTimeout * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveTimeout * 1000)]; } if (_callOptions.retryEnabled == NO) { @@ -119,15 +119,15 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if (_callOptions.connectMinTimeout > 0) { args[@GRPC_ARG_MIN_RECONNECT_BACKOFF_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMinTimeout * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMinTimeout * 1000)]; } if (_callOptions.connectInitialBackoff > 0) { args[@GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS] = [NSNumber - numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectInitialBackoff * 1000)]; + numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectInitialBackoff * 1000)]; } if (_callOptions.connectMaxBackoff > 0) { args[@GRPC_ARG_MAX_RECONNECT_BACKOFF_MS] = - [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMaxBackoff * 1000)]; + [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.connectMaxBackoff * 1000)]; } if (_callOptions.logContext != nil) { @@ -145,7 +145,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (nonnull id)copyWithZone:(nullable NSZone *)zone { GRPCChannelConfiguration *newConfig = - [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; + [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; return newConfig; } @@ -172,8 +172,6 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @end - - @implementation GRPCChannel { GRPCChannelConfiguration *_configuration; @@ -186,21 +184,24 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } @synthesize disconnected = _disconnected; -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { +- (nullable instancetype)initWithChannelConfiguration: + (GRPCChannelConfiguration *)channelConfiguration { return [self initWithChannelConfiguration:channelConfiguration destroyDelay:kDefaultChannelDestroyDelay]; } -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration +- (nullable instancetype)initWithChannelConfiguration: + (GRPCChannelConfiguration *)channelConfiguration destroyDelay:(NSTimeInterval)destroyDelay { - GRPCAssert(channelConfiguration != nil, NSInvalidArgumentException, @"channelConfiguration must not be empty."); + GRPCAssert(channelConfiguration != nil, NSInvalidArgumentException, + @"channelConfiguration must not be empty."); GRPCAssert(destroyDelay > 0, NSInvalidArgumentException, @"destroyDelay must be greater than 0."); if ((self = [super init])) { _configuration = [channelConfiguration copy]; if (@available(iOS 8.0, *)) { _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); } else { _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } @@ -244,7 +245,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; GRPCAssert(self->_unmanagedChannel != NULL, NSInvalidArgumentException, @"Invalid channel."); NSString *serverAuthority = - callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; + callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; GRPCAssert(timeout >= 0, NSInvalidArgumentException, @"Invalid timeout"); grpc_slice host_slice = grpc_empty_slice(); @@ -253,10 +254,10 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); gpr_timespec deadline_ms = - timeout == 0 - ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + timeout == 0 + ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); call = grpc_channel_create_call(self->_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, serverAuthority ? &host_slice : NULL, deadline_ms, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 24c0a8df11..48779c4449 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -44,8 +44,7 @@ NS_ASSUME_NONNULL_BEGIN * Return a channel with a particular configuration. If the channel does not exist, execute \a * createChannel then add it in the pool. If the channel exists, increase its reference count. */ -- (GRPCChannel *)channelWithHost:(NSString *)host - callOptions:(GRPCCallOptions *)callOptions; +- (GRPCChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; /** * This method is deprecated. diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 8a3b5edfa1..85ca527277 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -26,8 +26,8 @@ #import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" -#import "version.h" #import "utilities.h" +#import "version.h" #import #include @@ -62,11 +62,8 @@ static dispatch_once_t gInitChannelPool; return self; } -- (GRPCChannel *)channelWithHost:(NSString *)host - callOptions:(GRPCCallOptions *)callOptions { - return [self channelWithHost:host - callOptions:callOptions - destroyDelay:0]; +- (GRPCChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { + return [self channelWithHost:host callOptions:callOptions destroyDelay:0]; } - (GRPCChannel *)channelWithHost:(NSString *)host @@ -76,14 +73,15 @@ static dispatch_once_t gInitChannelPool; GRPCAssert(callOptions != nil, NSInvalidArgumentException, @"callOptions must not be empty."); GRPCChannel *channel; GRPCChannelConfiguration *configuration = - [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; + [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; @synchronized(self) { channel = _channelPool[configuration]; if (channel == nil || channel.disconnected) { if (destroyDelay == 0) { channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration]; } else { - channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration destroyDelay:destroyDelay]; + channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration + destroyDelay:destroyDelay]; } _channelPool[configuration] = channel; } @@ -91,8 +89,6 @@ static dispatch_once_t gInitChannelPool; return channel; } - - + (void)closeOpenConnections { [[GRPCChannelPool sharedInstance] destroyAllChannels]; } diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 14d07e949b..5fc7427b68 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -32,8 +32,8 @@ #import "GRPCCronetChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "NSDictionary+GRPC.h" -#import "version.h" #import "utilities.h" +#import "version.h" NS_ASSUME_NONNULL_BEGIN @@ -122,7 +122,8 @@ static NSMutableDictionary *gHostCache; if (_transportType == GRPCTransportTypeInsecure) { options.transportType = GRPCTransportTypeInsecure; } else { - GRPCAssert(_transportType == GRPCTransportTypeDefault, NSInvalidArgumentException, @"Invalid transport type"); + GRPCAssert(_transportType == GRPCTransportTypeDefault, NSInvalidArgumentException, + @"Invalid transport type"); options.transportType = GRPCTransportTypeCronet; } } else diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 3079394ed8..57bd40d678 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -84,8 +84,7 @@ NS_ASSUME_NONNULL_BEGIN *errorPtr = defaultRootsError; } GRPCAssertWithArgument( - defaultRootsASCII, - NSObjectNotAvailableException, + defaultRootsASCII, NSObjectNotAvailableException, @"Could not read gRPCCertificates.bundle/roots.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 " diff --git a/src/objective-c/GRPCClient/private/utilities.h b/src/objective-c/GRPCClient/private/utilities.h index c664e8bf9d..3e51730d63 100644 --- a/src/objective-c/GRPCClient/private/utilities.h +++ b/src/objective-c/GRPCClient/private/utilities.h @@ -19,17 +19,18 @@ #import /** Raise exception when condition not met. Disregard NS_BLOCK_ASSERTIONS. */ -#define GRPCAssert(condition, errorType, errorString) \ -do { \ -if (!(condition)) { \ -[NSException raise:(errorType) format:(errorString)]; \ -} \ -} while (0) +#define GRPCAssert(condition, errorType, errorString) \ + do { \ + if (!(condition)) { \ + [NSException raise:(errorType)format:(errorString)]; \ + } \ + } while (0) -/** The same as GRPCAssert but allows arguments to be put in the raised string. */ -#define GRPCAssertWithArgument(condition, errorType, errorFormat, ...) \ - do { \ - if (!(condition)) { \ - [NSException raise:(errorType) format:(errorFormat), __VA_ARGS__]; \ - } \ - } while (0) +/** The same as GRPCAssert but allows arguments to be put in the raised string. + */ +#define GRPCAssertWithArgument(condition, errorType, errorFormat, ...) \ + do { \ + if (!(condition)) { \ + [NSException raise:(errorType)format:(errorFormat), __VA_ARGS__]; \ + } \ + } while (0) -- cgit v1.2.3 From 94d220d32c0db708a3afa36a17aae25d93c2636b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 14:03:27 -0800 Subject: Rename variable --- .../transport/cronet/client/secure/cronet_channel_create.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc index dffb61b082..1cb38f25b6 100644 --- a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc +++ b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc @@ -47,11 +47,11 @@ GRPCAPI grpc_channel* grpc_cronet_secure_channel_create( target); // Disable client authority filter when using Cronet - grpc_arg arg; - arg.key = const_cast(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); - arg.type = GRPC_ARG_INTEGER; - arg.value.integer = 1; - grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args, &arg, 1); + grpc_arg disable_client_authority_filter_arg; + disable_client_authority_filter_arg.key = const_cast(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); + disable_client_authority_filter_arg.type = GRPC_ARG_INTEGER; + disable_client_authority_filter_arg.value.integer = 1; + grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args, &disable_client_authority_filter_arg, 1); grpc_transport* ct = grpc_create_cronet_transport(engine, target, new_args, reserved); -- cgit v1.2.3 From 8d0cf9ec0aaa9e9efd23254d189d78fbaead2702 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 14:03:50 -0800 Subject: clang-format --- .../tests/ChannelTests/ChannelPoolTest.m | 38 ++++++++-------------- src/objective-c/tests/ChannelTests/ChannelTests.m | 18 +++++----- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index d684db545e..b85e62feb5 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -47,14 +47,10 @@ NSString *kDummyHost = @"dummy.host"; GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - GRPCChannel *channel1 = [pool channelWithHost:kDummyHost - callOptions:options1]; - GRPCChannel *channel2 = [pool channelWithHost:kDummyHost - callOptions:options2]; - GRPCChannel *channel3 = [pool channelWithHost:kDummyHost2 - callOptions:options1]; - GRPCChannel *channel4 = [pool channelWithHost:kDummyHost - callOptions:options3]; + GRPCChannel *channel1 = [pool channelWithHost:kDummyHost callOptions:options1]; + GRPCChannel *channel2 = [pool channelWithHost:kDummyHost callOptions:options2]; + GRPCChannel *channel3 = [pool channelWithHost:kDummyHost2 callOptions:options1]; + GRPCChannel *channel4 = [pool channelWithHost:kDummyHost callOptions:options3]; XCTAssertEqual(channel1, channel2); XCTAssertNotEqual(channel1, channel3); XCTAssertNotEqual(channel1, channel4); @@ -66,16 +62,14 @@ NSString *kDummyHost = @"dummy.host"; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - GRPCChannel *channel = [pool channelWithHost:kDummyHost - callOptions:options]; + GRPCChannel *channel = [pool channelWithHost:kDummyHost callOptions:options]; grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" completionQueue:[GRPCCompletionQueue completionQueue] callOptions:options disconnected:nil]; [pool destroyAllChannels]; XCTAssertTrue(channel.disconnected); - GRPCChannel *channel2 = [pool channelWithHost:kDummyHost - callOptions:options]; + GRPCChannel *channel2 = [pool channelWithHost:kDummyHost callOptions:options]; XCTAssertNotEqual(channel, channel2); grpc_call_unref(call); } @@ -86,9 +80,8 @@ NSString *kDummyHost = @"dummy.host"; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - GRPCChannel *channel = [pool channelWithHost:kDummyHost - callOptions:options - destroyDelay:kDestroyDelay]; + GRPCChannel *channel = + [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" completionQueue:[GRPCCompletionQueue completionQueue] callOptions:options @@ -97,9 +90,8 @@ NSString *kDummyHost = @"dummy.host"; [channel unref]; // Test that we can still get the channel at this time - GRPCChannel *channel2 = [pool channelWithHost:kDummyHost - callOptions:options - destroyDelay:kDestroyDelay]; + GRPCChannel *channel2 = + [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; XCTAssertEqual(channel, channel2); call = [channel2 unmanagedCallWithPath:@"dummy.path" completionQueue:[GRPCCompletionQueue completionQueue] @@ -117,9 +109,8 @@ NSString *kDummyHost = @"dummy.host"; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - GRPCChannel *channel = [pool channelWithHost:kDummyHost - callOptions:options - destroyDelay:kDestroyDelay]; + GRPCChannel *channel = + [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" completionQueue:[GRPCCompletionQueue completionQueue] callOptions:options @@ -130,9 +121,8 @@ NSString *kDummyHost = @"dummy.host"; sleep(kDestroyDelay + 1); // Test that we get new channel to the same host and with the same callOptions - GRPCChannel *channel2 = [pool channelWithHost:kDummyHost - callOptions:options - destroyDelay:kDestroyDelay]; + GRPCChannel *channel2 = + [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; XCTAssertNotEqual(channel, channel2); } diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index 27e76d4179..5daafcdf3f 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -33,12 +33,13 @@ } - (void)testTimedDisconnection { - NSString * const kHost = @"grpc-test.sandbox.googleapis.com"; + NSString *const kHost = @"grpc-test.sandbox.googleapis.com"; const NSTimeInterval kDestroyDelay = 1; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; - GRPCChannel *channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration - destroyDelay:kDestroyDelay]; + GRPCChannelConfiguration *configuration = + [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; + GRPCChannel *channel = + [[GRPCChannel alloc] initWithChannelConfiguration:configuration destroyDelay:kDestroyDelay]; BOOL disconnected; grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" completionQueue:[GRPCCompletionQueue completionQueue] @@ -61,12 +62,13 @@ } - (void)testForceDisconnection { - NSString * const kHost = @"grpc-test.sandbox.googleapis.com"; + NSString *const kHost = @"grpc-test.sandbox.googleapis.com"; const NSTimeInterval kDestroyDelay = 1; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; - GRPCChannel *channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration - destroyDelay:kDestroyDelay]; + GRPCChannelConfiguration *configuration = + [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; + GRPCChannel *channel = + [[GRPCChannel alloc] initWithChannelConfiguration:configuration destroyDelay:kDestroyDelay]; grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" completionQueue:[GRPCCompletionQueue completionQueue] callOptions:options -- cgit v1.2.3 From b77203fdf59faa38e7be01f8796d3bc3e67db602 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 14:09:41 -0800 Subject: Move blocks into varibles for readability --- src/objective-c/GRPCClient/GRPCCall.m | 53 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 5e3491dafa..39681d2adf 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -172,7 +172,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (self->_callOptions.initialMetadata) { [self->_call.requestHeaders addEntriesFromDictionary:self->_callOptions.initialMetadata]; } - id responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(id value) { + + void (^valueHandler)(id value) = ^(id value) { dispatch_async(self->_dispatchQueue, ^{ if (self->_handler) { if (!self->_initialMetadataPublished) { @@ -184,30 +185,32 @@ const char *kCFStreamVarName = "grpc_cfstream"; } } }); - } - completionHandler:^(NSError *errorOrNil) { - dispatch_async(self->_dispatchQueue, ^{ - if (self->_handler) { - if (!self->_initialMetadataPublished) { - self->_initialMetadataPublished = YES; - [self issueInitialMetadata:self->_call.responseHeaders]; - } - [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; - - // Clean up _handler so that no more responses are reported to the handler. - self->_handler = nil; - } - // Clearing _call must happen *after* dispatching close in order to get trailing - // metadata from _call. - if (self->_call) { - // Clean up the request writers. This should have no effect to _call since its - // response writeable is already nullified. - [self->_pipe writesFinishedWithError:nil]; - self->_call = nil; - self->_pipe = nil; - } - }); - }]; + }; + void (^completionHandler)(NSError *errorOrNil) = ^(NSError *errorOrNil) { + dispatch_async(self->_dispatchQueue, ^{ + if (self->_handler) { + if (!self->_initialMetadataPublished) { + self->_initialMetadataPublished = YES; + [self issueInitialMetadata:self->_call.responseHeaders]; + } + [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; + + // Clean up _handler so that no more responses are reported to the handler. + self->_handler = nil; + } + // Clearing _call must happen *after* dispatching close in order to get trailing + // metadata from _call. + if (self->_call) { + // Clean up the request writers. This should have no effect to _call since its + // response writeable is already nullified. + [self->_pipe writesFinishedWithError:nil]; + self->_call = nil; + self->_pipe = nil; + } + }); + }; + id responseWriteable = [[GRXWriteable alloc] initWithValueHandler:valueHandler + completionHandler:completionHandler]; [self->_call startWithWriteable:responseWriteable]; }); } -- cgit v1.2.3 From 78c2176afcdf2267467c68f6f070fc6543673bd7 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 14:40:44 -0800 Subject: Assign finished and canceled --- src/objective-c/GRPCClient/GRPCCall.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 39681d2adf..9d81dcf6e6 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -143,7 +143,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); _started = NO; _canceled = NO; - _finished = YES; + _finished = NO; } return self; @@ -218,6 +218,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancel { dispatch_async(_dispatchQueue, ^{ GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call already canceled."); + self->_canceled = YES; if (self->_call) { [self->_call cancel]; self->_call = nil; @@ -263,6 +264,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; [self->_pipe writesFinishedWithError:nil]; } self->_pipe = nil; + self->_finished = YES; }); } -- cgit v1.2.3 From f4a77ce4926064e193787521081e835bd94f1e7d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 14:51:07 -0800 Subject: _call->_pipe --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 9d81dcf6e6..46cd5a4f22 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -260,7 +260,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; GRPCAssert(self->_started, NSInternalInconsistencyException, @"Call not started."); GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call arleady canceled."); GRPCAssert(!self->_finished, NSInternalInconsistencyException, @"Call already half-closed."); - if (self->_call) { + if (self->_pipe) { [self->_pipe writesFinishedWithError:nil]; } self->_pipe = nil; -- cgit v1.2.3 From c83ab56fe1d4bc6e5c3cebbc4943505eaf6ea74a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 14:51:25 -0800 Subject: copy->mutableCopy --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 46cd5a4f22..6de7bd8967 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -581,7 +581,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; break; } - NSMutableDictionary *headers = [_requestHeaders copy]; + NSMutableDictionary *headers = [_requestHeaders mutableCopy]; NSString *fetchedOauth2AccessToken; @synchronized(self) { fetchedOauth2AccessToken = _fetchedOauth2AccessToken; -- cgit v1.2.3 From b22120f69601450d4cbdc6957f661ba7ec29ca3a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 16:10:10 -0800 Subject: Test fix --- src/objective-c/tests/APIv2Tests/APIv2Tests.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index d681163419..28f94cd8c7 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -277,6 +277,7 @@ static const NSTimeInterval kTestTimeout = 16; callOptions:options]; [call writeData:[NSData data]]; [call start]; + [call finish]; [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; } @@ -312,6 +313,7 @@ static const NSTimeInterval kTestTimeout = 16; callOptions:options]; [call writeData:[request data]]; [call start]; + [call finish]; [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; } -- cgit v1.2.3 From e023468e9a82a4338e30e57ab822c86406480b94 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 16:34:58 -0800 Subject: some nit fixes --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/GRPCClient/GRPCCallOptions.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannel.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 6de7bd8967..2a56514bdc 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -282,7 +282,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [_handler closedWithTrailingMetadata:_call.responseTrailers error:error]; + [_handler closedWithTrailingMetadata:trailingMetadata error:error]; } } diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index ecb517762b..9a36ee547c 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -45,7 +45,7 @@ static NSString *const kDefaultChannelPoolDomain = nil; static const NSUInteger kDefaultChannelID = 0; // Check if two objects are equal. Returns YES if both are nil; -BOOL areObjectsEqual(id obj1, id obj2) { +static BOOL areObjectsEqual(id obj1, id obj2) { if (obj1 == obj2) { return YES; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 6c58f4f387..32e68bb262 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN * Options of the corresponding call. Note that only the channel-related options are of interest to * this class. */ -@property(strong, readonly) GRPCCallOptions *callOptions; +@property(readonly) GRPCCallOptions *callOptions; /** Acquire the factory to generate a new channel with current configurations. */ @property(readonly) id channelFactory; -- cgit v1.2.3 From 2bd38f29df16b874bea254e001e3c40d6945c28c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 17:59:30 -0800 Subject: Batch fixes --- src/objective-c/GRPCClient/private/GRPCChannel.m | 17 ++++++++++------- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 7 +++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index fc0448bb96..52dacad9f5 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -84,7 +84,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING; NSString *userAgentPrefix = _callOptions.userAgentPrefix; - if (userAgentPrefix) { + if (userAgentPrefix.length != 0) { args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = [_callOptions.userAgentPrefix stringByAppendingFormat:@" %@", userAgent]; } else { @@ -242,7 +242,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if (self->_disconnected) { isDisconnected = YES; } else { - GRPCAssert(self->_unmanagedChannel != NULL, NSInvalidArgumentException, @"Invalid channel."); + GRPCAssert(self->_unmanagedChannel != NULL, NSInternalInconsistencyException, @"Channel should have valid unmanaged channel."); NSString *serverAuthority = callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; @@ -281,14 +281,17 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; // This function should be called on _dispatchQueue. - (void)ref { - _refcount++; - if (_refcount == 1 && _lastDispatch != nil) { - _lastDispatch = nil; - } + dispatch_sync(_dispatchQueue, ^{ + self->_refcount++; + if (self->_refcount == 1 && self->_lastDispatch != nil) { + self->_lastDispatch = nil; + } + }); } - (void)unref { dispatch_async(_dispatchQueue, ^{ + GRPCAssert(self->_refcount > 0, NSInternalInconsistencyException, @"Illegal reference count."); self->_refcount--; if (self->_refcount == 0 && !self->_disconnected) { // Start timer. @@ -298,7 +301,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; self->_lastDispatch = now; dispatch_after(delay, self->_dispatchQueue, ^{ // Timed disconnection. - if (self->_lastDispatch == now) { + if (!self->_disconnected && self->_lastDispatch == now) { grpc_channel_destroy(self->_unmanagedChannel); self->_unmanagedChannel = NULL; self->_disconnected = YES; diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 2358c7bb0a..f3fe8bac45 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -30,6 +30,7 @@ #import "NSData+GRPC.h" #import "NSDictionary+GRPC.h" #import "NSError+GRPC.h" +#import "utilities.h" #import "GRPCOpBatchLog.h" @@ -248,16 +249,14 @@ - (instancetype)initWithHost:(NSString *)host path:(NSString *)path callOptions:(GRPCCallOptions *)callOptions { - if (host.length == 0 || path.length == 0) { - [NSException raise:NSInvalidArgumentException format:@"path and host cannot be nil."]; - } + GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, @"path and host cannot be nil."); if ((self = [super init])) { // Each completion queue consumes one thread. There's a trade to be made between creating and // consuming too many threads and having contention of multiple calls in a single completion // queue. Currently we use a singleton queue. _queue = [GRPCCompletionQueue completionQueue]; - BOOL disconnected; + BOOL disconnected = NO; do { _channel = [[GRPCChannelPool sharedInstance] channelWithHost:host callOptions:callOptions]; if (_channel == nil) { -- cgit v1.2.3 From b5434c05aaaacfba9d6ef6882b6c1f3285a304e2 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 18:48:09 -0800 Subject: Make tests pass --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannel.m | 11 +++++------ src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 2a56514bdc..1ba55a7744 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -249,7 +249,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call arleady canceled."); GRPCAssert(!self->_finished, NSInternalInconsistencyException, @"Call is half-closed before sending data."); - if (self->_call) { + if (self->_pipe) { [self->_pipe writeValue:data]; } }); diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 52dacad9f5..f63157c974 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -281,15 +281,14 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; // This function should be called on _dispatchQueue. - (void)ref { - dispatch_sync(_dispatchQueue, ^{ - self->_refcount++; - if (self->_refcount == 1 && self->_lastDispatch != nil) { - self->_lastDispatch = nil; - } - }); + _refcount++; + if (_refcount == 1 && _lastDispatch != nil) { + _lastDispatch = nil; + } } - (void)unref { + NSLog(@"unref"); dispatch_async(_dispatchQueue, ^{ GRPCAssert(self->_refcount > 0, NSInternalInconsistencyException, @"Illegal reference count."); self->_refcount--; diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index f3fe8bac45..905719f464 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -325,7 +325,6 @@ - (void)dealloc { if (_call) { grpc_call_unref(_call); - [_channel unref]; } [_channel unref]; _channel = nil; -- cgit v1.2.3 From e14ec44b0ac1512bc3def0f2094be883d1b53c5f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 14 Nov 2018 18:52:35 -0800 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.m | 5 +++-- src/objective-c/GRPCClient/private/GRPCChannel.m | 3 ++- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 1ba55a7744..4068c3b460 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -209,8 +209,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; } }); }; - id responseWriteable = [[GRXWriteable alloc] initWithValueHandler:valueHandler - completionHandler:completionHandler]; + id responseWriteable = + [[GRXWriteable alloc] initWithValueHandler:valueHandler + completionHandler:completionHandler]; [self->_call startWithWriteable:responseWriteable]; }); } diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index f63157c974..2933ca7044 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -242,7 +242,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if (self->_disconnected) { isDisconnected = YES; } else { - GRPCAssert(self->_unmanagedChannel != NULL, NSInternalInconsistencyException, @"Channel should have valid unmanaged channel."); + GRPCAssert(self->_unmanagedChannel != NULL, NSInternalInconsistencyException, + @"Channel should have valid unmanaged channel."); NSString *serverAuthority = callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 905719f464..aa7d60786e 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -249,7 +249,8 @@ - (instancetype)initWithHost:(NSString *)host path:(NSString *)path callOptions:(GRPCCallOptions *)callOptions { - GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, @"path and host cannot be nil."); + GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, + @"path and host cannot be nil."); if ((self = [super init])) { // Each completion queue consumes one thread. There's a trade to be made between creating and -- cgit v1.2.3 From 7500528b15b3a47343a6483c1b71857cbe00244a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 15 Nov 2018 09:45:12 -0800 Subject: clang-format --- .../ext/transport/cronet/client/secure/cronet_channel_create.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc index 1cb38f25b6..6e08d27b21 100644 --- a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc +++ b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc @@ -48,10 +48,12 @@ GRPCAPI grpc_channel* grpc_cronet_secure_channel_create( // Disable client authority filter when using Cronet grpc_arg disable_client_authority_filter_arg; - disable_client_authority_filter_arg.key = const_cast(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); + disable_client_authority_filter_arg.key = + const_cast(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); disable_client_authority_filter_arg.type = GRPC_ARG_INTEGER; disable_client_authority_filter_arg.value.integer = 1; - grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args, &disable_client_authority_filter_arg, 1); + grpc_channel_args* new_args = grpc_channel_args_copy_and_add( + args, &disable_client_authority_filter_arg, 1); grpc_transport* ct = grpc_create_cronet_transport(engine, target, new_args, reserved); -- cgit v1.2.3 From 6b6ab2bdc9d03ffe85398451342a140320aac1dd Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 15 Nov 2018 12:22:38 -0800 Subject: Back to NSAssert --- src/objective-c/GRPCClient/GRPCCall.m | 37 ++++++++++------------ src/objective-c/GRPCClient/private/GRPCChannel.m | 22 ++++++------- .../GRPCClient/private/GRPCChannelPool.m | 6 ++-- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- .../GRPCClient/private/GRPCSecureChannelFactory.m | 2 +- .../GRPCClient/private/GRPCWrappedCall.m | 4 ++- src/objective-c/GRPCClient/private/utilities.h | 19 ++--------- 7 files changed, 39 insertions(+), 53 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 4068c3b460..788afeb6c3 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -68,8 +68,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; @implementation GRPCRequestOptions - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { - GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, - @"Host and Path cannot be empty"); + NSAssert(host.length != 0 && path.length != 0, @"Host and Path cannot be empty"); if ((self = [super init])) { _host = [host copy]; _path = [path copy]; @@ -116,11 +115,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler callOptions:(GRPCCallOptions *_Nullable)callOptions { - GRPCAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0, - NSInvalidArgumentException, @"Neither host nor path can be nil."); - GRPCAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, + NSAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0, + @"Neither host nor path can be nil."); + NSAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); - GRPCAssert(responseHandler != nil, NSInvalidArgumentException, @"Response handler required."); + NSAssert(responseHandler != nil, @"Response handler required."); if ((self = [super init])) { _requestOptions = [requestOptions copy]; @@ -157,8 +156,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)start { dispatch_async(_dispatchQueue, ^{ - GRPCAssert(!self->_started, NSInternalInconsistencyException, @"Call already started."); - GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call already canceled."); + NSAssert(!self->_started, @"Call already started."); + NSAssert(!self->_canceled, @"Call already canceled."); self->_started = YES; if (!self->_callOptions) { self->_callOptions = [[GRPCCallOptions alloc] init]; @@ -218,7 +217,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancel { dispatch_async(_dispatchQueue, ^{ - GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call already canceled."); + NSAssert(!self->_canceled, @"Call already canceled."); self->_canceled = YES; if (self->_call) { [self->_call cancel]; @@ -247,9 +246,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)writeData:(NSData *)data { dispatch_async(_dispatchQueue, ^{ - GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call arleady canceled."); - GRPCAssert(!self->_finished, NSInternalInconsistencyException, - @"Call is half-closed before sending data."); + NSAssert(!self->_canceled, @"Call arleady canceled."); + NSAssert(!self->_finished, @"Call is half-closed before sending data."); if (self->_pipe) { [self->_pipe writeValue:data]; } @@ -258,9 +256,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)finish { dispatch_async(_dispatchQueue, ^{ - GRPCAssert(self->_started, NSInternalInconsistencyException, @"Call not started."); - GRPCAssert(!self->_canceled, NSInternalInconsistencyException, @"Call arleady canceled."); - GRPCAssert(!self->_finished, NSInternalInconsistencyException, @"Call already half-closed."); + NSAssert(self->_started, @"Call not started."); + NSAssert(!self->_canceled, @"Call arleady canceled."); + NSAssert(!self->_finished, @"Call already half-closed."); if (self->_pipe) { [self->_pipe writesFinishedWithError:nil]; } @@ -409,10 +407,10 @@ const char *kCFStreamVarName = "grpc_cfstream"; requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. - GRPCAssert(host && path, NSInvalidArgumentException, @"Neither host nor path can be nil."); - GRPCAssert(safety <= GRPCCallSafetyCacheableRequest, NSInvalidArgumentException, + NSAssert(host && path, @"Neither host nor path can be nil."); + NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); - GRPCAssert(requestWriter.state == GRXWriterStateNotStarted, NSInvalidArgumentException, + NSAssert(requestWriter.state == GRXWriterStateNotStarted, @"The requests writer can't be already started."); if ((self = [super init])) { _host = [host copy]; @@ -798,8 +796,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; _callOptions = callOptions; } - GRPCAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, - NSInvalidArgumentException, + NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); if (_callOptions.authTokenProvider != nil) { @synchronized(self) { diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 2933ca7044..ab084fba48 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -40,8 +40,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @implementation GRPCChannelConfiguration - (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { - GRPCAssert(host.length, NSInvalidArgumentException, @"Host must not be empty."); - GRPCAssert(callOptions != nil, NSInvalidArgumentException, @"callOptions must not be empty."); + NSAssert(host.length, @"Host must not be empty."); + NSAssert(callOptions != nil, @"callOptions must not be empty."); if ((self = [super init])) { _host = [host copy]; _callOptions = [callOptions copy]; @@ -193,9 +193,9 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (nullable instancetype)initWithChannelConfiguration: (GRPCChannelConfiguration *)channelConfiguration destroyDelay:(NSTimeInterval)destroyDelay { - GRPCAssert(channelConfiguration != nil, NSInvalidArgumentException, + NSAssert(channelConfiguration != nil, @"channelConfiguration must not be empty."); - GRPCAssert(destroyDelay > 0, NSInvalidArgumentException, @"destroyDelay must be greater than 0."); + NSAssert(destroyDelay > 0, @"destroyDelay must be greater than 0."); if ((self = [super init])) { _configuration = [channelConfiguration copy]; if (@available(iOS 8.0, *)) { @@ -208,7 +208,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; // Create gRPC core channel object. NSString *host = channelConfiguration.host; - GRPCAssert(host.length != 0, NSInvalidArgumentException, @"host cannot be nil"); + NSAssert(host.length != 0, @"host cannot be nil"); NSDictionary *channelArgs; if (channelConfiguration.callOptions.additionalChannelArgs.count != 0) { NSMutableDictionary *args = [channelConfiguration.channelArgs mutableCopy]; @@ -233,22 +233,22 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions disconnected:(BOOL *)disconnected { - GRPCAssert(path.length, NSInvalidArgumentException, @"path must not be empty."); - GRPCAssert(queue, NSInvalidArgumentException, @"completionQueue must not be empty."); - GRPCAssert(callOptions, NSInvalidArgumentException, @"callOptions must not be empty."); + NSAssert(path.length, @"path must not be empty."); + NSAssert(queue, @"completionQueue must not be empty."); + NSAssert(callOptions, @"callOptions must not be empty."); __block BOOL isDisconnected = NO; __block grpc_call *call = NULL; dispatch_sync(_dispatchQueue, ^{ if (self->_disconnected) { isDisconnected = YES; } else { - GRPCAssert(self->_unmanagedChannel != NULL, NSInternalInconsistencyException, + NSAssert(self->_unmanagedChannel != NULL, @"Channel should have valid unmanaged channel."); NSString *serverAuthority = callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; - GRPCAssert(timeout >= 0, NSInvalidArgumentException, @"Invalid timeout"); + NSAssert(timeout >= 0, @"Invalid timeout"); grpc_slice host_slice = grpc_empty_slice(); if (serverAuthority) { host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); @@ -291,7 +291,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (void)unref { NSLog(@"unref"); dispatch_async(_dispatchQueue, ^{ - GRPCAssert(self->_refcount > 0, NSInternalInconsistencyException, @"Illegal reference count."); + NSAssert(self->_refcount > 0, @"Illegal reference count."); self->_refcount--; if (self->_refcount == 0 && !self->_disconnected) { // Start timer. diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 85ca527277..6745010bd4 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -44,7 +44,7 @@ static dispatch_once_t gInitChannelPool; + (nullable instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ gChannelPool = [[GRPCChannelPool alloc] init]; - GRPCAssert(gChannelPool != nil, NSMallocException, @"Cannot initialize global channel pool."); + NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool."); }); return gChannelPool; } @@ -69,8 +69,8 @@ static dispatch_once_t gInitChannelPool; - (GRPCChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions destroyDelay:(NSTimeInterval)destroyDelay { - GRPCAssert(host.length > 0, NSInvalidArgumentException, @"Host must not be empty."); - GRPCAssert(callOptions != nil, NSInvalidArgumentException, @"callOptions must not be empty."); + NSAssert(host.length > 0, @"Host must not be empty."); + NSAssert(callOptions != nil, @"callOptions must not be empty."); GRPCChannel *channel; GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 5fc7427b68..b693b926ba 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -122,7 +122,7 @@ static NSMutableDictionary *gHostCache; if (_transportType == GRPCTransportTypeInsecure) { options.transportType = GRPCTransportTypeInsecure; } else { - GRPCAssert(_transportType == GRPCTransportTypeDefault, NSInvalidArgumentException, + NSAssert(_transportType == GRPCTransportTypeDefault, @"Invalid transport type"); options.transportType = GRPCTransportTypeCronet; } diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 57bd40d678..f5e7a2b9e2 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -83,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN if (errorPtr) { *errorPtr = defaultRootsError; } - GRPCAssertWithArgument( + NSAssert( defaultRootsASCII, NSObjectNotAvailableException, @"Could not read gRPCCertificates.bundle/roots.pem. This file, " "with the root certificates, is needed to establish secure (TLS) connections. " diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index aa7d60786e..ae7f07f119 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -249,7 +249,7 @@ - (instancetype)initWithHost:(NSString *)host path:(NSString *)path callOptions:(GRPCCallOptions *)callOptions { - GRPCAssert(host.length != 0 && path.length != 0, NSInvalidArgumentException, + NSAssert(host.length != 0 && path.length != 0, @"path and host cannot be nil."); if ((self = [super init])) { @@ -261,6 +261,7 @@ do { _channel = [[GRPCChannelPool sharedInstance] channelWithHost:host callOptions:callOptions]; if (_channel == nil) { + NSAssert(_channel != nil, @"Failed to get a channel for the host."); NSLog(@"Failed to get a channel for the host."); return nil; } @@ -272,6 +273,7 @@ // connectivity monitor disconnection). } while (_call == NULL && disconnected); if (_call == nil) { + NSAssert(_channel != nil, @"Failed to get a channel for the host."); NSLog(@"Failed to create a call."); return nil; } diff --git a/src/objective-c/GRPCClient/private/utilities.h b/src/objective-c/GRPCClient/private/utilities.h index 3e51730d63..8f6baadcf7 100644 --- a/src/objective-c/GRPCClient/private/utilities.h +++ b/src/objective-c/GRPCClient/private/utilities.h @@ -18,19 +18,6 @@ #import -/** Raise exception when condition not met. Disregard NS_BLOCK_ASSERTIONS. */ -#define GRPCAssert(condition, errorType, errorString) \ - do { \ - if (!(condition)) { \ - [NSException raise:(errorType)format:(errorString)]; \ - } \ - } while (0) - -/** The same as GRPCAssert but allows arguments to be put in the raised string. - */ -#define GRPCAssertWithArgument(condition, errorType, errorFormat, ...) \ - do { \ - if (!(condition)) { \ - [NSException raise:(errorType)format:(errorFormat), __VA_ARGS__]; \ - } \ - } while (0) +/** Raise exception when condition not met. */ +#define GRPCAssert(condition, errorString) \ + NSAssert(condition, errorString) -- cgit v1.2.3 From 8a762d447813db1b1c3fe52b24e638581235460e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 15 Nov 2018 12:56:08 -0800 Subject: Polish nullability + something else --- src/objective-c/GRPCClient/GRPCCall.h | 28 ++++++------- src/objective-c/GRPCClient/GRPCCall.m | 4 +- src/objective-c/GRPCClient/GRPCCallOptions.h | 46 +++++++++++----------- src/objective-c/GRPCClient/private/GRPCChannel.h | 2 +- src/objective-c/GRPCClient/private/GRPCChannel.m | 10 ++--- .../GRPCClient/private/GRPCChannelFactory.h | 4 +- .../GRPCClient/private/GRPCChannelPool.m | 2 +- .../GRPCClient/private/GRPCConnectivityMonitor.m | 4 +- .../GRPCClient/private/GRPCCronetChannelFactory.m | 22 ++++------- .../private/GRPCInsecureChannelFactory.m | 10 ++--- .../GRPCClient/private/GRPCSecureChannelFactory.m | 22 +++++------ src/objective-c/ProtoRPC/ProtoRPC.h | 12 +++--- src/objective-c/ProtoRPC/ProtoRPC.m | 14 +++---- src/objective-c/tests/InteropTests.m | 8 ++-- 14 files changed, 86 insertions(+), 102 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index bde69f01c5..fcda4dc8ac 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -159,14 +159,14 @@ extern NSString *const kGRPCTrailersKey; * Issued when initial metadata is received from the server. The task must be scheduled onto the * dispatch queue in property \a dispatchQueue. */ -- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; +- (void)receivedInitialMetadata:(nullable NSDictionary *)initialMetadata; /** * Issued when a message is received from the server. The message is the raw data received from the * server, with decompression and without proto deserialization. The task must be scheduled onto the * dispatch queue in property \a dispatchQueue. */ -- (void)receivedRawMessage:(NSData *_Nullable)message; +- (void)receivedRawMessage:(nullable NSData *)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -175,8 +175,8 @@ extern NSString *const kGRPCTrailersKey; * error descriptions. The task must be scheduled onto the dispatch queue in property * \a dispatchQueue. */ -- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata - error:(NSError *_Nullable)error; +- (void)closedWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata + error:(nullable NSError *)error; @required @@ -234,7 +234,7 @@ extern NSString *const kGRPCTrailersKey; */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler - callOptions:(GRPCCallOptions *_Nullable)callOptions + callOptions:(nullable GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; /** * Convenience initializer for a call that uses default call options (see GRPCCallOptions.m for @@ -342,9 +342,9 @@ NS_ASSUME_NONNULL_END * host parameter should not contain the scheme (http:// or https://), only the name or IP addr * and the port number, for example @"localhost:5050". */ -- (instancetype _Null_unspecified)initWithHost:(NSString *_Null_unspecified)host - path:(NSString *_Null_unspecified)path - requestsWriter:(GRXWriter *_Null_unspecified)requestWriter; +- (null_unspecified instancetype)initWithHost:(null_unspecified NSString *)host + path:(null_unspecified NSString *)path + requestsWriter:(null_unspecified GRXWriter *)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and @@ -356,11 +356,11 @@ NS_ASSUME_NONNULL_END * The following methods are deprecated. */ + (void)setCallSafety:(GRPCCallSafety)callSafety - host:(NSString *_Null_unspecified)host - path:(NSString *_Null_unspecified)path; + host:(null_unspecified NSString *)host + path:(null_unspecified NSString *)path; @property(null_unspecified, atomic, copy, readwrite) NSString *serverName; @property NSTimeInterval timeout; -- (void)setResponseDispatchQueue:(dispatch_queue_t _Null_unspecified)queue; +- (void)setResponseDispatchQueue:(null_unspecified dispatch_queue_t)queue; @end @@ -371,11 +371,11 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; -- (id _Null_unspecified)objectForKeyedSubscript:(id _Null_unspecified)key; -- (void)setObject:(id _Null_unspecified)obj forKeyedSubscript:(id _Null_unspecified)key; +- (null_unspecified id)objectForKeyedSubscript:(null_unspecified id)key; +- (void)setObject:(null_unspecified id)obj forKeyedSubscript:(null_unspecified id)key; - (void)removeAllObjects; -- (void)removeObjectForKey:(id _Null_unspecified)key; +- (void)removeObjectForKey:(null_unspecified id)key; @end #pragma clang diagnostic push diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 788afeb6c3..68b51d8c84 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -114,7 +114,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)responseHandler - callOptions:(GRPCCallOptions *_Nullable)callOptions { + callOptions:(GRPCCallOptions *)callOptions { NSAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0, @"Neither host nor path can be nil."); NSAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, @@ -134,7 +134,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (@available(iOS 8.0, *)) { _dispatchQueue = dispatch_queue_create( NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { // Fallback on earlier versions _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index bb8a1d251a..61d8564286 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -78,7 +78,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * :authority header field of the call and performs an extra check that server's certificate * matches the :authority header. */ -@property(copy, readonly) NSString *serverAuthority; +@property(copy, readonly, nullable) NSString *serverAuthority; /** * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to @@ -94,18 +94,18 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * request's "authorization" header field. This parameter should not be used simultaneously with * \a authTokenProvider. */ -@property(copy, readonly) NSString *oauth2AccessToken; +@property(copy, readonly, nullable) NSString *oauth2AccessToken; /** * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken. */ -@property(readonly) id authTokenProvider; +@property(readonly, nullable) id authTokenProvider; /** * Initial metadata key-value pairs that should be included in the request. */ -@property(copy, readonly) NSDictionary *initialMetadata; +@property(copy, readonly, nullable) NSDictionary *initialMetadata; // Channel parameters; take into account of channel signature. @@ -113,7 +113,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * Custom string that is prefixed to a request's user-agent header field before gRPC's internal * user-agent string. */ -@property(copy, readonly) NSString *userAgentPrefix; +@property(copy, readonly, nullable) NSString *userAgentPrefix; /** * The size limit for the response received from server. If it is exceeded, an error with status @@ -152,7 +152,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * Specify channel args to be used for this call. For a list of channel args available, see * grpc/grpc_types.h */ -@property(copy, readonly) NSDictionary *additionalChannelArgs; +@property(copy, readonly, nullable) NSDictionary *additionalChannelArgs; // Parameters for SSL authentication. @@ -160,17 +160,17 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default * root certificates. */ -@property(copy, readonly) NSString *PEMRootCertificates; +@property(copy, readonly, nullable) NSString *PEMRootCertificates; /** * PEM format private key for client authentication, if required by the server. */ -@property(copy, readonly) NSString *PEMPrivateKey; +@property(copy, readonly, nullable) NSString *PEMPrivateKey; /** * PEM format certificate chain for client authentication, if required by the server. */ -@property(copy, readonly) NSString *PEMCertChain; +@property(copy, readonly, nullable) NSString *PEMCertChain; /** * Select the transport type to be used for this call. @@ -180,13 +180,13 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * Override the hostname during the TLS hostname validation process. */ -@property(copy, readonly) NSString *hostNameOverride; +@property(copy, readonly, nullable) NSString *hostNameOverride; /** * A string that specify the domain where channel is being cached. Channels with different domains * will not get cached to the same connection. */ -@property(copy, readonly) NSString *channelPoolDomain; +@property(copy, readonly, nullable) NSString *channelPoolDomain; /** * Channel id allows control of channel caching within a channelPoolDomain. A call with a unique @@ -199,7 +199,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * Return if the channel options are equal to another object. */ -- (BOOL)hasChannelOptionsEqualTo:(GRPCCallOptions *)callOptions; +- (BOOL)hasChannelOptionsEqualTo:(nonnull GRPCCallOptions *)callOptions; /** * Hash for channel options. @@ -219,7 +219,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * :authority header field of the call and performs an extra check that server's certificate * matches the :authority header. */ -@property(copy, readwrite) NSString *serverAuthority; +@property(copy, readwrite, nullable) NSString *serverAuthority; /** * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to @@ -236,18 +236,18 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * request's "authorization" header field. This parameter should not be used simultaneously with * \a authTokenProvider. */ -@property(copy, readwrite) NSString *oauth2AccessToken; +@property(copy, readwrite, nullable) NSString *oauth2AccessToken; /** * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken. */ -@property(readwrite) id authTokenProvider; +@property(readwrite, nullable) id authTokenProvider; /** * Initial metadata key-value pairs that should be included in the request. */ -@property(copy, readwrite) NSDictionary *initialMetadata; +@property(copy, readwrite, nullable) NSDictionary *initialMetadata; // Channel parameters; take into account of channel signature. @@ -255,7 +255,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * Custom string that is prefixed to a request's user-agent header field before gRPC's internal * user-agent string. */ -@property(copy, readwrite) NSString *userAgentPrefix; +@property(copy, readwrite, nullable) NSString *userAgentPrefix; /** * The size limit for the response received from server. If it is exceeded, an error with status @@ -296,7 +296,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * Specify channel args to be used for this call. For a list of channel args available, see * grpc/grpc_types.h */ -@property(copy, readwrite) NSDictionary *additionalChannelArgs; +@property(copy, readwrite, nullable) NSDictionary *additionalChannelArgs; // Parameters for SSL authentication. @@ -304,17 +304,17 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default * root certificates. */ -@property(copy, readwrite) NSString *PEMRootCertificates; +@property(copy, readwrite, nullable) NSString *PEMRootCertificates; /** * PEM format private key for client authentication, if required by the server. */ -@property(copy, readwrite) NSString *PEMPrivateKey; +@property(copy, readwrite, nullable) NSString *PEMPrivateKey; /** * PEM format certificate chain for client authentication, if required by the server. */ -@property(copy, readwrite) NSString *PEMCertChain; +@property(copy, readwrite, nullable) NSString *PEMCertChain; /** * Select the transport type to be used for this call. @@ -324,7 +324,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * Override the hostname during the TLS hostname validation process. */ -@property(copy, readwrite) NSString *hostNameOverride; +@property(copy, readwrite, nullable) NSString *hostNameOverride; /** * A string that specify the domain where channel is being cached. Channels with different domains @@ -332,7 +332,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * domain 'io.grpc.example' so that its calls do not reuse the channel created by other modules in * the same process. */ -@property(copy, readwrite) NSString *channelPoolDomain; +@property(copy, readwrite, nullable) NSString *channelPoolDomain; /** * Channel id allows a call to force creating a new channel (connection) rather than using a cached diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 32e68bb262..4dbe0c276c 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -85,7 +85,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions - disconnected:(BOOL *_Nullable)disconnected; + disconnected:(nullable BOOL *)disconnected; /** * Unref the channel when a call is done. It also decreases the channel's refcount. If the refcount diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index ab084fba48..de3302598e 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -39,7 +39,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @implementation GRPCChannelConfiguration -- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { +- (instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { NSAssert(host.length, @"Host must not be empty."); NSAssert(callOptions != nil, @"callOptions must not be empty."); if ((self = [super init])) { @@ -143,7 +143,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; return args; } -- (nonnull id)copyWithZone:(nullable NSZone *)zone { +- (id)copyWithZone:(NSZone *)zone { GRPCChannelConfiguration *newConfig = [[GRPCChannelConfiguration alloc] initWithHost:_host callOptions:_callOptions]; @@ -184,13 +184,13 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } @synthesize disconnected = _disconnected; -- (nullable instancetype)initWithChannelConfiguration: +- (instancetype)initWithChannelConfiguration: (GRPCChannelConfiguration *)channelConfiguration { return [self initWithChannelConfiguration:channelConfiguration destroyDelay:kDefaultChannelDestroyDelay]; } -- (nullable instancetype)initWithChannelConfiguration: +- (instancetype)initWithChannelConfiguration: (GRPCChannelConfiguration *)channelConfiguration destroyDelay:(NSTimeInterval)destroyDelay { NSAssert(channelConfiguration != nil, @@ -201,7 +201,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if (@available(iOS 8.0, *)) { _dispatchQueue = dispatch_queue_create( NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h index 3a3500fc95..a934e966e9 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h @@ -26,8 +26,8 @@ NS_ASSUME_NONNULL_BEGIN @protocol GRPCChannelFactory /** Create a channel with specific channel args to a specific host. */ -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args; +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSDictionary *)args; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 6745010bd4..72554ca6dc 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -41,7 +41,7 @@ static dispatch_once_t gInitChannelPool; NSMutableDictionary *_channelPool; } -+ (nullable instancetype)sharedInstance { ++ (instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ gChannelPool = [[GRPCChannelPool alloc] init]; NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool."); diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m index a36788b35a..bb8618ff33 100644 --- a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m +++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m @@ -76,14 +76,14 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach } } -+ (void)registerObserver:(_Nonnull id)observer selector:(SEL)selector { ++ (void)registerObserver:(id)observer selector:(SEL)selector { [[NSNotificationCenter defaultCenter] addObserver:observer selector:selector name:kGRPCConnectivityNotification object:nil]; } -+ (void)unregisterObserver:(_Nonnull id)observer { ++ (void)unregisterObserver:(id)observer { [[NSNotificationCenter defaultCenter] removeObserver:observer]; } diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index 781881d211..74ea9723b3 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -26,13 +26,11 @@ #import #include -NS_ASSUME_NONNULL_BEGIN - @implementation GRPCCronetChannelFactory { stream_engine *_cronetEngine; } -+ (instancetype _Nullable)sharedInstance { ++ (instancetype)sharedInstance { static GRPCCronetChannelFactory *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -41,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN return instance; } -- (instancetype _Nullable)initWithEngine:(stream_engine *)engine { +- (instancetype)initWithEngine:(stream_engine *)engine { if (!engine) { [NSException raise:NSInvalidArgumentException format:@"Cronet engine is NULL. Set it first."]; return nil; @@ -52,8 +50,8 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *)args { grpc_channel_args *channelArgs = GRPCBuildChannelArgs(args); grpc_channel *unmanagedChannel = grpc_cronet_secure_channel_create(_cronetEngine, host.UTF8String, channelArgs, NULL); @@ -63,22 +61,18 @@ NS_ASSUME_NONNULL_BEGIN @end -NS_ASSUME_NONNULL_END - #else -NS_ASSUME_NONNULL_BEGIN - @implementation GRPCCronetChannelFactory -+ (instancetype _Nullable)sharedInstance { ++ (instancetype)sharedInstance { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; return nil; } -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *)args { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; return NULL; @@ -86,6 +80,4 @@ NS_ASSUME_NONNULL_BEGIN @end -NS_ASSUME_NONNULL_END - #endif diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m index 9969887712..3e9ebe7ae0 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -21,11 +21,9 @@ #import "ChannelArgsUtil.h" #import "GRPCChannel.h" -NS_ASSUME_NONNULL_BEGIN - @implementation GRPCInsecureChannelFactory -+ (instancetype _Nullable)sharedInstance { ++ (instancetype)sharedInstance { static GRPCInsecureChannelFactory *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -34,8 +32,8 @@ NS_ASSUME_NONNULL_BEGIN return instance; } -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); @@ -44,5 +42,3 @@ NS_ASSUME_NONNULL_BEGIN } @end - -NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index f5e7a2b9e2..2e7f1a0dbe 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -24,15 +24,13 @@ #import "GRPCChannel.h" #import "utilities.h" -NS_ASSUME_NONNULL_BEGIN - @implementation GRPCSecureChannelFactory { grpc_channel_credentials *_channelCreds; } -+ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString *_Nullable)rootCerts - privateKey:(NSString *_Nullable)privateKey - certChain:(NSString *_Nullable)certChain ++ (instancetype)factoryWithPEMRootCertificates:(NSString *)rootCerts + privateKey:(NSString *)privateKey + certChain:(NSString *)certChain error:(NSError **)errorPtr { return [[self alloc] initWithPEMRootCerts:rootCerts privateKey:privateKey @@ -40,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN error:errorPtr]; } -- (NSData *_Nullable)nullTerminatedDataWithString:(NSString *_Nullable)string { +- (NSData *)nullTerminatedDataWithString:(NSString *)string { // dataUsingEncoding: does not return a null-terminated string. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; if (data == nil) { @@ -51,9 +49,9 @@ NS_ASSUME_NONNULL_BEGIN return nullTerminated; } -- (instancetype _Nullable)initWithPEMRootCerts:(NSString *_Nullable)rootCerts - privateKey:(NSString *_Nullable)privateKey - certChain:(NSString *_Nullable)certChain +- (instancetype)initWithPEMRootCerts:(NSString *)rootCerts + privateKey:(NSString *)privateKey + certChain:(NSString *)certChain error:(NSError **)errorPtr { static NSData *defaultRootsASCII; static NSError *defaultRootsError; @@ -117,8 +115,8 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); @@ -133,5 +131,3 @@ NS_ASSUME_NONNULL_BEGIN } @end - -NS_ASSUME_NONNULL_END diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index b0f4ced99e..dc776368a8 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -33,13 +33,13 @@ NS_ASSUME_NONNULL_BEGIN /** * Issued when initial metadata is received from the server. The task must be scheduled onto the * dispatch queue in property \a dispatchQueue. */ -- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata; +- (void)receivedInitialMetadata:(nullable NSDictionary *)initialMetadata; /** * Issued when a message is received from the server. The message is the deserialized proto object. * The task must be scheduled onto the dispatch queue in property \a dispatchQueue. */ -- (void)receivedProtoMessage:(GPBMessage *_Nullable)message; +- (void)receivedProtoMessage:(nullable GPBMessage *)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -48,8 +48,8 @@ NS_ASSUME_NONNULL_BEGIN * error descriptions. The task must be scheduled onto the dispatch queue in property * \a dispatchQueue. */ -- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata - error:(NSError *_Nullable)error; +- (void)closedWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata + error:(nullable NSError *)error; @required @@ -75,7 +75,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message responseHandler:(id)handler - callOptions:(GRPCCallOptions *_Nullable)callOptions + callOptions:(nullable GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** @@ -100,7 +100,7 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)handler - callOptions:(GRPCCallOptions *_Nullable)callOptions + callOptions:(nullable GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 34891e8953..f99da45fef 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -52,7 +52,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions message:(GPBMessage *)message responseHandler:(id)handler - callOptions:(GRPCCallOptions *_Nullable)callOptions + callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { if ((self = [super init])) { _call = [[GRPCStreamingProtoCall alloc] initWithRequestOptions:requestOptions @@ -88,7 +88,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions responseHandler:(id)handler - callOptions:(GRPCCallOptions *_Nullable)callOptions + callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; @@ -108,7 +108,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing if (@available(iOS 8.0, *)) { _dispatchQueue = dispatch_queue_create( NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, -1)); + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); } @@ -171,7 +171,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing }); } -- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { dispatch_async(_dispatchQueue, ^{ if (initialMetadata != nil && [self->_handler respondsToSelector:@selector(initialMetadata:)]) { [self->_handler receivedInitialMetadata:initialMetadata]; @@ -179,7 +179,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing }); } -- (void)receivedRawMessage:(NSData *_Nullable)message { +- (void)receivedRawMessage:(NSData *)message { dispatch_async(_dispatchQueue, ^{ if (self->_handler && message != nil) { NSError *error = nil; @@ -202,8 +202,8 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing }); } -- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata - error:(NSError *_Nullable)error { +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata + error:(NSError *)error { dispatch_async(_dispatchQueue, ^{ if ([self->_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { [self->_handler closedWithTrailingMetadata:trailingMetadata error:error]; diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index c42718f15e..dcc8f1b589 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -102,7 +102,7 @@ BOOL isRemoteInteropTest(NSString *host) { return self; } -- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { dispatch_async(_dispatchQueue, ^{ if (_initialMetadataCallback) { _initialMetadataCallback(initialMetadata); @@ -110,7 +110,7 @@ BOOL isRemoteInteropTest(NSString *host) { }); } -- (void)receivedProtoMessage:(GPBMessage *_Nullable)message { +- (void)receivedProtoMessage:(GPBMessage *)message { dispatch_async(_dispatchQueue, ^{ if (_messageCallback) { _messageCallback(message); @@ -118,8 +118,8 @@ BOOL isRemoteInteropTest(NSString *host) { }); } -- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata - error:(NSError *_Nullable)error { +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata + error:(NSError *)error { dispatch_async(_dispatchQueue, ^{ if (_closeCallback) { _closeCallback(trailingMetadata, error); -- cgit v1.2.3 From 57464321214a5ce34e5de1868ce4eb3624ebdebb Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 15 Nov 2018 14:00:51 -0800 Subject: Fix handler release - Part 1 --- src/objective-c/GRPCClient/GRPCCall.h | 9 +++------ src/objective-c/ProtoRPC/ProtoRPC.h | 7 ++----- src/objective-c/tests/APIv2Tests/APIv2Tests.m | 24 +++++++++--------------- src/objective-c/tests/InteropTests.m | 24 +++++++++--------------- 4 files changed, 23 insertions(+), 41 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index fcda4dc8ac..7f80c17f1f 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -156,15 +156,13 @@ extern NSString *const kGRPCTrailersKey; @optional /** - * Issued when initial metadata is received from the server. The task must be scheduled onto the - * dispatch queue in property \a dispatchQueue. + * Issued when initial metadata is received from the server. */ - (void)receivedInitialMetadata:(nullable NSDictionary *)initialMetadata; /** * Issued when a message is received from the server. The message is the raw data received from the - * server, with decompression and without proto deserialization. The task must be scheduled onto the - * dispatch queue in property \a dispatchQueue. + * server, with decompression and without proto deserialization. */ - (void)receivedRawMessage:(nullable NSData *)message; @@ -172,8 +170,7 @@ extern NSString *const kGRPCTrailersKey; * Issued when a call finished. If the call finished successfully, \a error is nil and \a * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error * is non-nil and contains the corresponding error information, including gRPC error codes and - * error descriptions. The task must be scheduled onto the dispatch queue in property - * \a dispatchQueue. + * error descriptions. */ - (void)closedWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata error:(nullable NSError *)error; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index dc776368a8..569aaa79e4 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -31,13 +31,11 @@ NS_ASSUME_NONNULL_BEGIN @optional /** - * Issued when initial metadata is received from the server. The task must be scheduled onto the - * dispatch queue in property \a dispatchQueue. */ + * Issued when initial metadata is received from the server. - (void)receivedInitialMetadata:(nullable NSDictionary *)initialMetadata; /** * Issued when a message is received from the server. The message is the deserialized proto object. - * The task must be scheduled onto the dispatch queue in property \a dispatchQueue. */ - (void)receivedProtoMessage:(nullable GPBMessage *)message; @@ -45,8 +43,7 @@ NS_ASSUME_NONNULL_BEGIN * Issued when a call finished. If the call finished successfully, \a error is nil and \a * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error * is non-nil and contains the corresponding error information, including gRPC error codes and - * error descriptions. The task must be scheduled onto the dispatch queue in property - * \a dispatchQueue. + * error descriptions. */ - (void)closedWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata error:(nullable NSError *)error; diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index 28f94cd8c7..e49f58ae9d 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -82,28 +82,22 @@ static const NSTimeInterval kTestTimeout = 16; } - (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { - dispatch_async(_dispatchQueue, ^{ - if (self->_initialMetadataCallback) { - self->_initialMetadataCallback(initialMetadata); - } - }); + if (self->_initialMetadataCallback) { + self->_initialMetadataCallback(initialMetadata); + } } - (void)receivedRawMessage:(GPBMessage *_Nullable)message { - dispatch_async(_dispatchQueue, ^{ - if (self->_messageCallback) { - self->_messageCallback(message); - } - }); + if (self->_messageCallback) { + self->_messageCallback(message); + } } - (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata error:(NSError *_Nullable)error { - dispatch_async(_dispatchQueue, ^{ - if (self->_closeCallback) { - self->_closeCallback(trailingMetadata, error); - } - }); + if (self->_closeCallback) { + self->_closeCallback(trailingMetadata, error); + } } - (dispatch_queue_t)dispatchQueue { diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index dcc8f1b589..8754bd5cca 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -103,28 +103,22 @@ BOOL isRemoteInteropTest(NSString *host) { } - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { - dispatch_async(_dispatchQueue, ^{ - if (_initialMetadataCallback) { - _initialMetadataCallback(initialMetadata); - } - }); + if (_initialMetadataCallback) { + _initialMetadataCallback(initialMetadata); + } } - (void)receivedProtoMessage:(GPBMessage *)message { - dispatch_async(_dispatchQueue, ^{ - if (_messageCallback) { - _messageCallback(message); - } - }); + if (_messageCallback) { + _messageCallback(message); + } } - (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - dispatch_async(_dispatchQueue, ^{ - if (_closeCallback) { - _closeCallback(trailingMetadata, error); - } - }); + if (_closeCallback) { + _closeCallback(trailingMetadata, error); + } } - (dispatch_queue_t)dispatchQueue { -- cgit v1.2.3 From ffeb0e682393e5b76d732e0b034c71f3837b9e57 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 15 Nov 2018 14:56:50 -0800 Subject: Add *if* after assert --- src/objective-c/GRPCClient/GRPCCall.m | 54 ++++++++++++++++++++++ src/objective-c/GRPCClient/private/GRPCChannel.m | 25 ++++++++-- .../GRPCClient/private/GRPCChannelPool.m | 3 ++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 68b51d8c84..f340e2bd8c 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -69,6 +69,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { NSAssert(host.length != 0 && path.length != 0, @"Host and Path cannot be empty"); + if (host.length == 0) { + host = [NSString string]; + } + if (path.length == 0) { + path = [NSString string]; + } if ((self = [super init])) { _host = [host copy]; _path = [path copy]; @@ -120,6 +126,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; NSAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); NSAssert(responseHandler != nil, @"Response handler required."); + if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { + return nil; + } + if (requestOptions.safety > GRPCCallSafetyCacheableRequest) { + return nil; + } + if (responseHandler == nil) { + return nil; + } + if ((self = [super init])) { _requestOptions = [requestOptions copy]; @@ -158,6 +174,13 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_async(_dispatchQueue, ^{ NSAssert(!self->_started, @"Call already started."); NSAssert(!self->_canceled, @"Call already canceled."); + if (self->_started) { + return; + } + if (self->_canceled) { + return; + } + self->_started = YES; if (!self->_callOptions) { self->_callOptions = [[GRPCCallOptions alloc] init]; @@ -218,6 +241,10 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)cancel { dispatch_async(_dispatchQueue, ^{ NSAssert(!self->_canceled, @"Call already canceled."); + if (self->_canceled) { + return; + } + self->_canceled = YES; if (self->_call) { [self->_call cancel]; @@ -248,6 +275,13 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_async(_dispatchQueue, ^{ NSAssert(!self->_canceled, @"Call arleady canceled."); NSAssert(!self->_finished, @"Call is half-closed before sending data."); + if (self->_canceled) { + return; + } + if (self->_finished) { + return; + } + if (self->_pipe) { [self->_pipe writeValue:data]; } @@ -259,6 +293,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; NSAssert(self->_started, @"Call not started."); NSAssert(!self->_canceled, @"Call arleady canceled."); NSAssert(!self->_finished, @"Call already half-closed."); + if (!self->_started) { + return; + } + if (self->_canceled) { + return; + } + if (self->_finished) { + return; + } + if (self->_pipe) { [self->_pipe writesFinishedWithError:nil]; } @@ -412,6 +456,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; @"Invalid call safety value."); NSAssert(requestWriter.state == GRXWriterStateNotStarted, @"The requests writer can't be already started."); + if (!host || !path) { + return nil; + } + if (safety > GRPCCallSafetyCacheableRequest) { + return nil; + } + if (requestWriter.state != GRXWriterStateNotStarted) { + return nil; + } + if ((self = [super init])) { _host = [host copy]; _path = [path copy]; diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index de3302598e..a19802b010 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -40,8 +40,11 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @implementation GRPCChannelConfiguration - (instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { - NSAssert(host.length, @"Host must not be empty."); + NSAssert(host.length > 0, @"Host must not be empty."); NSAssert(callOptions != nil, @"callOptions must not be empty."); + if (host.length == 0) return nil; + if (callOptions == nil) return nil; + if ((self = [super init])) { _host = [host copy]; _callOptions = [callOptions copy]; @@ -196,6 +199,9 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; NSAssert(channelConfiguration != nil, @"channelConfiguration must not be empty."); NSAssert(destroyDelay > 0, @"destroyDelay must be greater than 0."); + if (channelConfiguration == nil) return nil; + if (destroyDelay <= 0) return nil; + if ((self = [super init])) { _configuration = [channelConfiguration copy]; if (@available(iOS 8.0, *)) { @@ -219,6 +225,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } id factory = channelConfiguration.channelFactory; _unmanagedChannel = [factory createChannelWithHost:host channelArgs:channelArgs]; + NSAssert(_unmanagedChannel != NULL, @"Failed to create channel"); if (_unmanagedChannel == NULL) { NSLog(@"Unable to create channel."); return nil; @@ -233,9 +240,13 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions disconnected:(BOOL *)disconnected { - NSAssert(path.length, @"path must not be empty."); - NSAssert(queue, @"completionQueue must not be empty."); - NSAssert(callOptions, @"callOptions must not be empty."); + NSAssert(path.length > 0, @"path must not be empty."); + NSAssert(queue != nil, @"completionQueue must not be empty."); + NSAssert(callOptions != nil, @"callOptions must not be empty."); + if (path.length == 0) return nil; + if (queue == nil) return nil; + if (callOptions == nil) return nil; + __block BOOL isDisconnected = NO; __block grpc_call *call = NULL; dispatch_sync(_dispatchQueue, ^{ @@ -244,11 +255,13 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } else { NSAssert(self->_unmanagedChannel != NULL, @"Channel should have valid unmanaged channel."); + if (self->_unmanagedChannel == NULL) return; NSString *serverAuthority = callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; NSAssert(timeout >= 0, @"Invalid timeout"); + if (timeout < 0) return; grpc_slice host_slice = grpc_empty_slice(); if (serverAuthority) { host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); @@ -292,6 +305,10 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; NSLog(@"unref"); dispatch_async(_dispatchQueue, ^{ NSAssert(self->_refcount > 0, @"Illegal reference count."); + if (self->_refcount == 0) { + NSLog(@"Illegal reference count."); + return; + } self->_refcount--; if (self->_refcount == 0 && !self->_disconnected) { // Start timer. diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 72554ca6dc..5e2e9bcfeb 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -71,6 +71,9 @@ static dispatch_once_t gInitChannelPool; destroyDelay:(NSTimeInterval)destroyDelay { NSAssert(host.length > 0, @"Host must not be empty."); NSAssert(callOptions != nil, @"callOptions must not be empty."); + if (host.length == 0) return nil; + if (callOptions == nil) return nil; + GRPCChannel *channel; GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; -- cgit v1.2.3 From 512c01bc574ab09129608bc501d80f06503c79a3 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 15 Nov 2018 16:59:31 -0800 Subject: Polish threading + something else --- src/objective-c/GRPCClient/GRPCCall.m | 241 +++++++++++++---------- src/objective-c/GRPCClient/private/GRPCChannel.m | 1 - src/objective-c/ProtoRPC/ProtoRPC.h | 1 + src/objective-c/ProtoRPC/ProtoRPC.m | 123 +++++++----- 4 files changed, 209 insertions(+), 157 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index f340e2bd8c..ede16b42e8 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -155,7 +155,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Fallback on earlier versions _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } - dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); + dispatch_set_target_queue(_dispatchQueue ,responseHandler.dispatchQueue); _started = NO; _canceled = NO; _finished = NO; @@ -171,161 +171,194 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)start { - dispatch_async(_dispatchQueue, ^{ - NSAssert(!self->_started, @"Call already started."); - NSAssert(!self->_canceled, @"Call already canceled."); - if (self->_started) { + GRPCCall *call = nil; + @synchronized (self) { + NSAssert(!_started, @"Call already started."); + NSAssert(!_canceled, @"Call already canceled."); + if (_started) { return; } - if (self->_canceled) { + if (_canceled) { return; } - self->_started = YES; - if (!self->_callOptions) { - self->_callOptions = [[GRPCCallOptions alloc] init]; + _started = YES; + if (!_callOptions) { + _callOptions = [[GRPCCallOptions alloc] init]; } - self->_call = [[GRPCCall alloc] initWithHost:self->_requestOptions.host - path:self->_requestOptions.path - callSafety:self->_requestOptions.safety - requestsWriter:self->_pipe - callOptions:self->_callOptions]; - if (self->_callOptions.initialMetadata) { - [self->_call.requestHeaders addEntriesFromDictionary:self->_callOptions.initialMetadata]; + _call = [[GRPCCall alloc] initWithHost:_requestOptions.host + path:_requestOptions.path + callSafety:_requestOptions.safety + requestsWriter:_pipe + callOptions:_callOptions]; + if (_callOptions.initialMetadata) { + [_call.requestHeaders addEntriesFromDictionary:_callOptions.initialMetadata]; } + call = _call; + } - void (^valueHandler)(id value) = ^(id value) { - dispatch_async(self->_dispatchQueue, ^{ - if (self->_handler) { - if (!self->_initialMetadataPublished) { - self->_initialMetadataPublished = YES; - [self issueInitialMetadata:self->_call.responseHeaders]; - } - if (value) { - [self issueMessage:value]; - } + void (^valueHandler)(id value) = ^(id value) { + @synchronized (self) { + if (self->_handler) { + if (!self->_initialMetadataPublished) { + self->_initialMetadataPublished = YES; + [self issueInitialMetadata:self->_call.responseHeaders]; } - }); - }; - void (^completionHandler)(NSError *errorOrNil) = ^(NSError *errorOrNil) { - dispatch_async(self->_dispatchQueue, ^{ - if (self->_handler) { - if (!self->_initialMetadataPublished) { - self->_initialMetadataPublished = YES; - [self issueInitialMetadata:self->_call.responseHeaders]; - } - [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; - - // Clean up _handler so that no more responses are reported to the handler. - self->_handler = nil; + if (value) { + [self issueMessage:value]; } - // Clearing _call must happen *after* dispatching close in order to get trailing - // metadata from _call. - if (self->_call) { - // Clean up the request writers. This should have no effect to _call since its - // response writeable is already nullified. - [self->_pipe writesFinishedWithError:nil]; - self->_call = nil; - self->_pipe = nil; + } + } + }; + void (^completionHandler)(NSError *errorOrNil) = ^(NSError *errorOrNil) { + @synchronized(self) { + if (self->_handler) { + if (!self->_initialMetadataPublished) { + self->_initialMetadataPublished = YES; + [self issueInitialMetadata:self->_call.responseHeaders]; } - }); - }; - id responseWriteable = - [[GRXWriteable alloc] initWithValueHandler:valueHandler - completionHandler:completionHandler]; - [self->_call startWithWriteable:responseWriteable]; - }); + [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; + + } + // Clearing _call must happen *after* dispatching close in order to get trailing + // metadata from _call. + if (self->_call) { + // Clean up the request writers. This should have no effect to _call since its + // response writeable is already nullified. + [self->_pipe writesFinishedWithError:nil]; + self->_call = nil; + self->_pipe = nil; + } + } + }; + id responseWriteable = + [[GRXWriteable alloc] initWithValueHandler:valueHandler + completionHandler:completionHandler]; + [call startWithWriteable:responseWriteable]; } - (void)cancel { - dispatch_async(_dispatchQueue, ^{ - NSAssert(!self->_canceled, @"Call already canceled."); - if (self->_canceled) { + GRPCCall *call = nil; + @synchronized (self) { + if (_canceled) { return; } - self->_canceled = YES; - if (self->_call) { - [self->_call cancel]; - self->_call = nil; - self->_pipe = nil; - } - if (self->_handler) { - id handler = self->_handler; - dispatch_async(handler.dispatchQueue, ^{ - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [handler closedWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + _canceled = YES; + + call = _call; + _call = nil; + _pipe = nil; + + if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(_dispatchQueue, ^{ + // Copy to local so that block is freed after cancellation completes. + id copiedHandler = nil; + @synchronized (self) { + copiedHandler = self->_handler; + self->_handler = nil; } - }); - // Clean up _handler so that no more responses are reported to the handler. - self->_handler = nil; + [copiedHandler closedWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + }); } - }); + } + [call cancel]; } - (void)writeData:(NSData *)data { - dispatch_async(_dispatchQueue, ^{ - NSAssert(!self->_canceled, @"Call arleady canceled."); - NSAssert(!self->_finished, @"Call is half-closed before sending data."); - if (self->_canceled) { + GRXBufferedPipe *pipe = nil; + @synchronized(self) { + NSAssert(!_canceled, @"Call arleady canceled."); + NSAssert(!_finished, @"Call is half-closed before sending data."); + if (_canceled) { return; } - if (self->_finished) { + if (_finished) { return; } - if (self->_pipe) { - [self->_pipe writeValue:data]; + if (_pipe) { + pipe = _pipe; } - }); + } + [pipe writeValue:data]; } - (void)finish { - dispatch_async(_dispatchQueue, ^{ - NSAssert(self->_started, @"Call not started."); - NSAssert(!self->_canceled, @"Call arleady canceled."); - NSAssert(!self->_finished, @"Call already half-closed."); - if (!self->_started) { + GRXBufferedPipe *pipe = nil; + @synchronized(self) { + NSAssert(_started, @"Call not started."); + NSAssert(!_canceled, @"Call arleady canceled."); + NSAssert(!_finished, @"Call already half-closed."); + if (!_started) { return; } - if (self->_canceled) { + if (_canceled) { return; } - if (self->_finished) { + if (_finished) { return; } - if (self->_pipe) { - [self->_pipe writesFinishedWithError:nil]; + if (_pipe) { + pipe = _pipe; + _pipe = nil; } - self->_pipe = nil; - self->_finished = YES; - }); + _finished = YES; + } + [pipe writesFinishedWithError:nil]; } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { - if (initialMetadata != nil && [_handler respondsToSelector:@selector(receivedInitialMetadata:)]) { - [_handler receivedInitialMetadata:initialMetadata]; + @synchronized (self) { + if (initialMetadata != nil && [_handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + dispatch_async(_dispatchQueue, ^{ + id handler = nil; + @synchronized (self) { + handler = self->_handler; + } + [handler receivedInitialMetadata:initialMetadata]; + }); + } } } - (void)issueMessage:(id)message { - if (message != nil && [_handler respondsToSelector:@selector(receivedRawMessage:)]) { - [_handler receivedRawMessage:message]; + @synchronized (self) { + if (message != nil && [_handler respondsToSelector:@selector(receivedRawMessage:)]) { + dispatch_async(_dispatchQueue, ^{ + id handler = nil; + @synchronized (self) { + handler = self->_handler; + } + [handler receivedRawMessage:message]; + }); + } } } - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [_handler closedWithTrailingMetadata:trailingMetadata error:error]; + @synchronized (self) { + if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(_dispatchQueue, ^{ + id handler = nil; + @synchronized (self) { + handler = self->_handler; + // Clean up _handler so that no more responses are reported to the handler. + self->_handler = nil; + } + [handler closedWithTrailingMetadata:trailingMetadata + error:error]; + }); + } } } diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index a19802b010..997d1ff663 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -302,7 +302,6 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } - (void)unref { - NSLog(@"unref"); dispatch_async(_dispatchQueue, ^{ NSAssert(self->_refcount > 0, @"Illegal reference count."); if (self->_refcount == 0) { diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 569aaa79e4..98b60c3f72 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Issued when initial metadata is received from the server. + */ - (void)receivedInitialMetadata:(nullable NSDictionary *)initialMetadata; /** diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index f99da45fef..9f45bdfcd4 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -112,7 +112,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } else { _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); } - dispatch_set_target_queue(handler.dispatchQueue, _dispatchQueue); + dispatch_set_target_queue(_dispatchQueue, handler.dispatchQueue); [self start]; } @@ -127,15 +127,17 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)cancel { - dispatch_async(_dispatchQueue, ^{ - if (_call) { - [_call cancel]; - _call = nil; - } - if (_handler) { - id handler = _handler; - if ([handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - dispatch_async(handler.dispatchQueue, ^{ + GRPCCall2 *call; + @synchronized(self) { + call = _call; + _call = nil; + if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(_handler.dispatchQueue, ^{ + id handler = nil; + @synchronized(self) { + handler = self->_handler; + self->_handler = nil; + } [handler closedWithTrailingMetadata:nil error:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeCancelled @@ -145,9 +147,8 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing }]]; }); } - _handler = nil; - } - }); + } + [call cancel]; } - (void)writeMessage:(GPBMessage *)message { @@ -155,63 +156,81 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing [NSException raise:NSInvalidArgumentException format:@"Data must be a valid protobuf type."]; } - dispatch_async(_dispatchQueue, ^{ - if (_call) { - [_call writeData:[message data]]; - } - }); + GRPCCall2 *call; + @synchronized(self) { + call = _call; + } + [call writeData:[message data]]; } - (void)finish { - dispatch_async(_dispatchQueue, ^{ - if (_call) { - [_call finish]; - _call = nil; - } - }); + GRPCCall2 *call; + @synchronized(self) { + call = _call; + _call = nil; + } + [call finish]; } - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { - dispatch_async(_dispatchQueue, ^{ - if (initialMetadata != nil && [self->_handler respondsToSelector:@selector(initialMetadata:)]) { - [self->_handler receivedInitialMetadata:initialMetadata]; + @synchronized (self) { + if (initialMetadata != nil && [_handler respondsToSelector:@selector(initialMetadata:)]) { + dispatch_async(_dispatchQueue, ^{ + id handler = nil; + @synchronized (self) { + handler = self->_handler; + } + [handler receivedInitialMetadata:initialMetadata]; + }); } - }); + } } - (void)receivedRawMessage:(NSData *)message { - dispatch_async(_dispatchQueue, ^{ - if (self->_handler && message != nil) { - NSError *error = nil; - GPBMessage *parsed = [self->_responseClass parseFromData:message error:&error]; - if (parsed) { - if ([self->_handler respondsToSelector:@selector(receivedProtoMessage:)]) { - [self->_handler receivedProtoMessage:parsed]; + if (message == nil) return; + + NSError *error = nil; + GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; + @synchronized (self) { + if (parsed && [_handler respondsToSelector:@selector(receivedProtoMessage:)]) { + dispatch_async(_dispatchQueue, ^{ + id handler = nil; + @synchronized (self) { + handler = self->_handler; } - } else { - if ([self->_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [self->_handler - closedWithTrailingMetadata:nil - error:ErrorForBadProto(message, _responseClass, error)]; + [handler receivedProtoMessage:parsed]; + }); + } else if (!parsed && [_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]){ + dispatch_async(_dispatchQueue, ^{ + id handler = nil; + @synchronized (self) { + handler = self->_handler; + self->_handler = nil; } - self->_handler = nil; - [self->_call cancel]; - self->_call = nil; - } + [handler closedWithTrailingMetadata:nil + error:ErrorForBadProto(message, _responseClass, error)]; + }); + [_call cancel]; + _call = nil; } - }); + } } - (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - dispatch_async(_dispatchQueue, ^{ - if ([self->_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - [self->_handler closedWithTrailingMetadata:trailingMetadata error:error]; + @synchronized (self) { + if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + dispatch_async(_dispatchQueue, ^{ + id handler = nil; + @synchronized (self) { + handler = self->_handler; + self->_handler = nil; + } + [handler closedWithTrailingMetadata:trailingMetadata error:error]; + }); } - self->_handler = nil; - [self->_call cancel]; - self->_call = nil; - }); + _call = nil; + } } - (dispatch_queue_t)dispatchQueue { -- cgit v1.2.3 From 87abab45c99ab4b40718557cbc1c25dcd7f5a418 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 15 Nov 2018 17:44:26 -0800 Subject: Fix version availability --- src/objective-c/GRPCClient/GRPCCall.m | 8 ++++++-- src/objective-c/GRPCClient/private/GRPCChannel.m | 7 +++++-- src/objective-c/ProtoRPC/ProtoRPC.m | 8 +++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index ede16b42e8..19de004cbc 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -147,12 +147,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; _handler = responseHandler; _initialMetadataPublished = NO; _pipe = [GRXBufferedPipe pipe]; - if (@available(iOS 8.0, *)) { + // Set queue QoS only when iOS version is 8.0 or above and Xcode version is 9.0 or above +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + if (@available(iOS 8.0, macOS 10.10, *)) { _dispatchQueue = dispatch_queue_create( NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { - // Fallback on earlier versions +#else + { +#endif _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } dispatch_set_target_queue(_dispatchQueue ,responseHandler.dispatchQueue); diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 997d1ff663..0220141db0 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -204,14 +204,17 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if ((self = [super init])) { _configuration = [channelConfiguration copy]; - if (@available(iOS 8.0, *)) { +#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED < 101300 + if (@available(iOS 8.0, macOS 10.10, *)) { _dispatchQueue = dispatch_queue_create( NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { +#else + { +#endif _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } - // Create gRPC core channel object. NSString *host = channelConfiguration.host; NSAssert(host.length != 0, @"host cannot be nil"); diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 9f45bdfcd4..9164f2320b 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -105,11 +105,17 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing _handler = handler; _callOptions = [callOptions copy]; _responseClass = responseClass; - if (@available(iOS 8.0, *)) { + + // Set queue QoS only when iOS version is 8.0 or above and Xcode version is 9.0 or above +#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED < 101300 + if (@available(iOS 8.0, macOS 10.10, *)) { _dispatchQueue = dispatch_queue_create( NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { +#else + { +#endif _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); } dispatch_set_target_queue(_dispatchQueue, handler.dispatchQueue); -- cgit v1.2.3 From f0cbcde73195b8e17130538c3479d4c0e3bcd2a2 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sun, 18 Nov 2018 22:47:35 -0800 Subject: New channel pool design --- src/objective-c/GRPCClient/GRPCCall+ChannelArg.m | 2 +- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/GRPCClient/private/GRPCChannel.h | 36 +-- src/objective-c/GRPCClient/private/GRPCChannel.m | 169 +++---------- .../GRPCClient/private/GRPCChannelPool.h | 74 +++++- .../GRPCClient/private/GRPCChannelPool.m | 263 ++++++++++++++++++--- .../GRPCClient/private/GRPCWrappedCall.m | 31 +-- .../tests/ChannelTests/ChannelPoolTest.m | 222 ++++++++++------- src/objective-c/tests/ChannelTests/ChannelTests.m | 126 ++++++---- 9 files changed, 573 insertions(+), 352 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m index 971c2803e2..703cff63bb 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m @@ -36,7 +36,7 @@ } + (void)closeOpenConnections { - [GRPCChannelPool closeOpenConnections]; + [[GRPCChannelPool sharedInstance] closeOpenConnections]; } + (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm forhost:(nonnull NSString *)host { diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 19de004cbc..6f4b1647a5 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -488,7 +488,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. - NSAssert(host && path, @"Neither host nor path can be nil."); + NSAssert(host != nil && path != nil, @"Neither host nor path can be nil."); NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); NSAssert(requestWriter.state == GRXWriterStateNotStarted, diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 4dbe0c276c..de6d1bf4a2 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -61,47 +61,19 @@ NS_ASSUME_NONNULL_BEGIN + (nullable instancetype) new NS_UNAVAILABLE; /** - * Create a channel with remote \a host and signature \a channelConfigurations. Destroy delay is - * defaulted to 30 seconds. - */ -- (nullable instancetype)initWithChannelConfiguration: - (GRPCChannelConfiguration *)channelConfiguration; - -/** - * Create a channel with remote \a host, signature \a channelConfigurations, and destroy delay of - * \a destroyDelay. + * Create a channel with remote \a host and signature \a channelConfigurations. */ - (nullable instancetype)initWithChannelConfiguration: (GRPCChannelConfiguration *)channelConfiguration - destroyDelay:(NSTimeInterval)destroyDelay NS_DESIGNATED_INITIALIZER; /** - * Create a grpc core call object from this channel. The channel's refcount is added by 1. If no - * call is created, NULL is returned, and if the reason is because the channel is already - * disconnected, \a disconnected is set to YES. When the returned call is unreffed, the caller is - * obligated to call \a unref method once. \a disconnected may be null. + * Create a grpc core call object (grpc_call) from this channel. If no call is created, NULL is + * returned. */ - (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue - callOptions:(GRPCCallOptions *)callOptions - disconnected:(nullable BOOL *)disconnected; - -/** - * Unref the channel when a call is done. It also decreases the channel's refcount. If the refcount - * of the channel decreases to 0, the channel is destroyed after the destroy delay. - */ -- (void)unref; - -/** - * Force the channel to be disconnected and destroyed. - */ -- (void)disconnect; - -/** - * Return whether the channel is already disconnected. - */ -@property(readonly) BOOL disconnected; + callOptions:(GRPCCallOptions *)callOptions; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 0220141db0..81e53d48e3 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -34,9 +34,6 @@ #import #import -/** When all calls of a channel are destroyed, destroy the channel after this much seconds. */ -static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - @implementation GRPCChannelConfiguration - (instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { @@ -178,43 +175,18 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @implementation GRPCChannel { GRPCChannelConfiguration *_configuration; - dispatch_queue_t _dispatchQueue; grpc_channel *_unmanagedChannel; - NSTimeInterval _destroyDelay; - - NSUInteger _refcount; - NSDate *_lastDispatch; -} -@synthesize disconnected = _disconnected; - -- (instancetype)initWithChannelConfiguration: - (GRPCChannelConfiguration *)channelConfiguration { - return [self initWithChannelConfiguration:channelConfiguration - destroyDelay:kDefaultChannelDestroyDelay]; } - (instancetype)initWithChannelConfiguration: - (GRPCChannelConfiguration *)channelConfiguration - destroyDelay:(NSTimeInterval)destroyDelay { + (GRPCChannelConfiguration *)channelConfiguration { NSAssert(channelConfiguration != nil, @"channelConfiguration must not be empty."); - NSAssert(destroyDelay > 0, @"destroyDelay must be greater than 0."); if (channelConfiguration == nil) return nil; - if (destroyDelay <= 0) return nil; if ((self = [super init])) { _configuration = [channelConfiguration copy]; -#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED < 101300 - if (@available(iOS 8.0, macOS 10.10, *)) { - _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); - } else { -#else - { -#endif - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } + // Create gRPC core channel object. NSString *host = channelConfiguration.host; NSAssert(host.length != 0, @"host cannot be nil"); @@ -233,119 +205,54 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; NSLog(@"Unable to create channel."); return nil; } - _destroyDelay = destroyDelay; - _disconnected = NO; } return self; } - (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue - callOptions:(GRPCCallOptions *)callOptions - disconnected:(BOOL *)disconnected { + callOptions:(GRPCCallOptions *)callOptions { NSAssert(path.length > 0, @"path must not be empty."); NSAssert(queue != nil, @"completionQueue must not be empty."); NSAssert(callOptions != nil, @"callOptions must not be empty."); - if (path.length == 0) return nil; - if (queue == nil) return nil; - if (callOptions == nil) return nil; - - __block BOOL isDisconnected = NO; - __block grpc_call *call = NULL; - dispatch_sync(_dispatchQueue, ^{ - if (self->_disconnected) { - isDisconnected = YES; - } else { - NSAssert(self->_unmanagedChannel != NULL, - @"Channel should have valid unmanaged channel."); - if (self->_unmanagedChannel == NULL) return; - - NSString *serverAuthority = - callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; - NSTimeInterval timeout = callOptions.timeout; - NSAssert(timeout >= 0, @"Invalid timeout"); - if (timeout < 0) return; - grpc_slice host_slice = grpc_empty_slice(); - if (serverAuthority) { - host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); - } - grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); - gpr_timespec deadline_ms = - timeout == 0 - ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); - call = grpc_channel_create_call(self->_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, - queue.unmanagedQueue, path_slice, - serverAuthority ? &host_slice : NULL, deadline_ms, NULL); - if (serverAuthority) { - grpc_slice_unref(host_slice); - } - grpc_slice_unref(path_slice); - if (call == NULL) { - NSLog(@"Unable to create call."); - } else { - // Ref the channel; - [self ref]; - } + if (path.length == 0) return NULL; + if (queue == nil) return NULL; + if (callOptions == nil) return NULL; + + grpc_call *call = NULL; + @synchronized(self) { + NSAssert(_unmanagedChannel != NULL, + @"Channel should have valid unmanaged channel."); + if (_unmanagedChannel == NULL) return NULL; + + NSString *serverAuthority = + callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; + NSTimeInterval timeout = callOptions.timeout; + NSAssert(timeout >= 0, @"Invalid timeout"); + if (timeout < 0) return NULL; + grpc_slice host_slice = grpc_empty_slice(); + if (serverAuthority) { + host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); } - }); - if (disconnected != nil) { - *disconnected = isDisconnected; - } - return call; -} - -// This function should be called on _dispatchQueue. -- (void)ref { - _refcount++; - if (_refcount == 1 && _lastDispatch != nil) { - _lastDispatch = nil; - } -} - -- (void)unref { - dispatch_async(_dispatchQueue, ^{ - NSAssert(self->_refcount > 0, @"Illegal reference count."); - if (self->_refcount == 0) { - NSLog(@"Illegal reference count."); - return; + grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); + gpr_timespec deadline_ms = + timeout == 0 + ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + call = grpc_channel_create_call(_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, + queue.unmanagedQueue, path_slice, + serverAuthority ? &host_slice : NULL, deadline_ms, NULL); + if (serverAuthority) { + grpc_slice_unref(host_slice); } - self->_refcount--; - if (self->_refcount == 0 && !self->_disconnected) { - // Start timer. - dispatch_time_t delay = - dispatch_time(DISPATCH_TIME_NOW, (int64_t)self->_destroyDelay * NSEC_PER_SEC); - NSDate *now = [NSDate date]; - self->_lastDispatch = now; - dispatch_after(delay, self->_dispatchQueue, ^{ - // Timed disconnection. - if (!self->_disconnected && self->_lastDispatch == now) { - grpc_channel_destroy(self->_unmanagedChannel); - self->_unmanagedChannel = NULL; - self->_disconnected = YES; - } - }); + grpc_slice_unref(path_slice); + NSAssert(call != nil, @"Unable to create call."); + if (call == NULL) { + NSLog(@"Unable to create call."); } - }); -} - -- (void)disconnect { - dispatch_async(_dispatchQueue, ^{ - if (!self->_disconnected) { - grpc_channel_destroy(self->_unmanagedChannel); - self->_unmanagedChannel = nil; - self->_disconnected = YES; - } - }); -} - -- (BOOL)disconnected { - __block BOOL disconnected; - dispatch_sync(_dispatchQueue, ^{ - disconnected = self->_disconnected; - }); - return disconnected; + } + return call; } - (void)dealloc { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 48779c4449..887bd5f89f 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -27,7 +27,53 @@ NS_ASSUME_NONNULL_BEGIN +@protocol GRPCChannel; @class GRPCChannel; +@class GRPCChannelPool; +@class GRPCCompletionQueue; +@class GRPCChannelConfiguration; + +/** + * Channel proxy that can be retained and automatically reestablish connection when the channel is + * disconnected. + */ +@interface GRPCPooledChannel : NSObject + +/** + * Initialize with an actual channel object \a channel and a reference to the channel pool. + */ +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration + channelPool:(GRPCChannelPool *)channelPool; + + +/** + * Create a grpc core call object (grpc_call) from this channel. If channel is disconnected, get a + * new channel object from the channel pool. + */ +- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path + completionQueue:(GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions; + +/** + * Return ownership and destroy the grpc_call object created by + * \a unmanagedCallWithPath:completionQueue:callOptions: and decrease channel refcount. If refcount + * of the channel becomes 0, return the channel object to channel pool. + */ +- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall; + +/** + * Force the channel to disconnect immediately. + */ +- (void)disconnect; + +// The following methods and properties are for test only + +/** + * Return the pointer to the real channel wrapped by the proxy. + */ +@property(atomic, readonly) GRPCChannel *wrappedChannel; + +@end /** * Manage the pool of connected channels. When a channel is no longer referenced by any call, @@ -36,37 +82,41 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCChannelPool : NSObject /** - * Get the singleton instance + * Get the global channel pool. */ + (nullable instancetype)sharedInstance; /** - * Return a channel with a particular configuration. If the channel does not exist, execute \a - * createChannel then add it in the pool. If the channel exists, increase its reference count. + * Return a channel with a particular configuration. The channel may be a cached channel. */ -- (GRPCChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; +- (GRPCPooledChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; /** * This method is deprecated. * * Destroy all open channels and close their connections. */ -+ (void)closeOpenConnections; +- (void)closeOpenConnections; // Test-only methods below /** - * Return a channel with a special destroy delay. If \a destroyDelay is 0, use the default destroy - * delay. + * Get an instance of pool isolated from the global shared pool. This method is for test only. + * Global pool should be used in production. + */ +- (nullable instancetype)init; + +/** + * Simulate a network transition event and destroy all channels. This method is for internal and + * test only. */ -- (GRPCChannel *)channelWithHost:(NSString *)host - callOptions:(GRPCCallOptions *)callOptions - destroyDelay:(NSTimeInterval)destroyDelay; +- (void)disconnectAllChannels; /** - * Simulate a network transition event and destroy all channels. + * Set the destroy delay of channels. A channel should be destroyed if it stayed idle (no active + * call on it) for this period of time. This property is for test only. */ -- (void)destroyAllChannels; +@property(atomic) NSTimeInterval destroyDelay; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 5e2e9bcfeb..92dd4c86ae 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -37,8 +37,150 @@ extern const char *kCFStreamVarName; static GRPCChannelPool *gChannelPool; static dispatch_once_t gInitChannelPool; +/** When all calls of a channel are destroyed, destroy the channel after this much seconds. */ +static const NSTimeInterval kDefaultChannelDestroyDelay = 30; + +@interface GRPCChannelPool() + +- (GRPCChannel *)refChannelWithConfiguration:(GRPCChannelConfiguration *)configuration; + +- (void)unrefChannelWithConfiguration:(GRPCChannelConfiguration *)configuration; + +@end + +@implementation GRPCPooledChannel { + __weak GRPCChannelPool *_channelPool; + GRPCChannelConfiguration *_channelConfiguration; + NSMutableSet *_unmanagedCalls; +} + +@synthesize wrappedChannel = _wrappedChannel; + +- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration + channelPool:(GRPCChannelPool *)channelPool { + NSAssert(channelConfiguration != nil, @"channelConfiguration cannot be empty."); + NSAssert(channelPool != nil, @"channelPool cannot be empty."); + if (channelPool == nil || channelConfiguration == nil) { + return nil; + } + + if ((self = [super init])) { + _channelPool = channelPool; + _channelConfiguration = channelConfiguration; + _unmanagedCalls = [NSMutableSet set]; + } + + return self; +} + +- (grpc_call *)unmanagedCallWithPath:(NSString *)path + completionQueue:(GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions { + NSAssert(path.length > 0, @"path must not be empty."); + NSAssert(queue != nil, @"completionQueue must not be empty."); + NSAssert(callOptions, @"callOptions must not be empty."); + if (path.length == 0 || queue == nil || callOptions == nil) return NULL; + + grpc_call *call = NULL; + @synchronized(self) { + if (_wrappedChannel == nil) { + __strong GRPCChannelPool *strongPool = _channelPool; + if (strongPool) { + _wrappedChannel = [strongPool refChannelWithConfiguration:_channelConfiguration]; + } + NSAssert(_wrappedChannel != nil, @"Unable to get a raw channel for proxy."); + } + call = [_wrappedChannel unmanagedCallWithPath:path completionQueue:queue callOptions:callOptions]; + if (call != NULL) { + [_unmanagedCalls addObject:[NSValue valueWithPointer:call]]; + } + } + return call; +} + +- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall { + if (unmanagedCall == nil) return; + + grpc_call_unref(unmanagedCall); + BOOL timedDestroy = NO; + @synchronized(self) { + if ([_unmanagedCalls containsObject:[NSValue valueWithPointer:unmanagedCall]]) { + [_unmanagedCalls removeObject:[NSValue valueWithPointer:unmanagedCall]]; + if ([_unmanagedCalls count] == 0) { + timedDestroy = YES; + } + } + } + if (timedDestroy) { + [self timedDestroy]; + } +} + +- (void)disconnect { + @synchronized(self) { + _wrappedChannel = nil; + [_unmanagedCalls removeAllObjects]; + } +} + +- (GRPCChannel *)wrappedChannel { + GRPCChannel *channel = nil; + @synchronized (self) { + channel = _wrappedChannel; + } + return channel; +} + +- (void)timedDestroy { + __strong GRPCChannelPool *pool = nil; + @synchronized(self) { + // Check if we still want to destroy the channel. + if ([_unmanagedCalls count] == 0) { + pool = _channelPool; + _wrappedChannel = nil; + } + } + [pool unrefChannelWithConfiguration:_channelConfiguration]; +} + +@end + +/** + * A convenience value type for cached channel. + */ +@interface GRPCChannelRecord : NSObject + +/** Pointer to the raw channel. May be nil when the channel has been destroyed. */ +@property GRPCChannel *channel; + +/** Channel proxy corresponding to this channel configuration. */ +@property GRPCPooledChannel *proxy; + +/** Last time when a timed destroy is initiated on the channel. */ +@property NSDate *timedDestroyDate; + +/** Reference count of the proxy to the channel. */ +@property NSUInteger refcount; + +@end + +@implementation GRPCChannelRecord + +- (id)copyWithZone:(NSZone *)zone { + GRPCChannelRecord *newRecord = [[GRPCChannelRecord allocWithZone:zone] init]; + newRecord.channel = _channel; + newRecord.proxy = _proxy; + newRecord.timedDestroyDate = _timedDestroyDate; + newRecord.refcount = _refcount; + + return newRecord; +} + +@end + @implementation GRPCChannelPool { - NSMutableDictionary *_channelPool; + NSMutableDictionary *_channelPool; + dispatch_queue_t _dispatchQueue; } + (instancetype)sharedInstance { @@ -52,6 +194,18 @@ static dispatch_once_t gInitChannelPool; - (instancetype)init { if ((self = [super init])) { _channelPool = [NSMutableDictionary dictionary]; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + if (@available(iOS 8.0, macOS 10.10, *)) { + _dispatchQueue = dispatch_queue_create( + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); + } else { +#else + { +#endif + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } + _destroyDelay = kDefaultChannelDestroyDelay; // Connectivity monitor is not required for CFStream char *enableCFStream = getenv(kCFStreamVarName); @@ -62,51 +216,106 @@ static dispatch_once_t gInitChannelPool; return self; } -- (GRPCChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { - return [self channelWithHost:host callOptions:callOptions destroyDelay:0]; -} - -- (GRPCChannel *)channelWithHost:(NSString *)host - callOptions:(GRPCCallOptions *)callOptions - destroyDelay:(NSTimeInterval)destroyDelay { +- (GRPCPooledChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { NSAssert(host.length > 0, @"Host must not be empty."); NSAssert(callOptions != nil, @"callOptions must not be empty."); if (host.length == 0) return nil; if (callOptions == nil) return nil; - GRPCChannel *channel; + GRPCPooledChannel *channelProxy = nil; GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; @synchronized(self) { - channel = _channelPool[configuration]; - if (channel == nil || channel.disconnected) { - if (destroyDelay == 0) { - channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration]; - } else { - channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration - destroyDelay:destroyDelay]; - } - _channelPool[configuration] = channel; + GRPCChannelRecord *record = _channelPool[configuration]; + if (record == nil) { + record = [[GRPCChannelRecord alloc] init]; + record.proxy = [[GRPCPooledChannel alloc] initWithChannelConfiguration:configuration + channelPool:self]; + record.timedDestroyDate = nil; + _channelPool[configuration] = record; + channelProxy = record.proxy; + } else { + channelProxy = record.proxy; } } - return channel; + return channelProxy; } -+ (void)closeOpenConnections { - [[GRPCChannelPool sharedInstance] destroyAllChannels]; +- (void)closeOpenConnections { + [self disconnectAllChannels]; } -- (void)destroyAllChannels { - @synchronized(self) { - for (id key in _channelPool) { - [_channelPool[key] disconnect]; +- (GRPCChannel *)refChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { + GRPCChannel *ret = nil; + @synchronized (self) { + NSAssert(configuration != nil, @"configuration cannot be empty."); + if (configuration == nil) return nil; + + GRPCChannelRecord *record = _channelPool[configuration]; + NSAssert(record != nil, @"No record corresponding to a proxy."); + if (record == nil) return nil; + + if (record.channel == nil) { + // Channel is already destroyed; + record.channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration]; + record.timedDestroyDate = nil; + record.refcount = 1; + ret = record.channel; + } else { + ret = record.channel; + record.timedDestroyDate = nil; + record.refcount++; } - _channelPool = [NSMutableDictionary dictionary]; } + return ret; +} + +- (void)unrefChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { + @synchronized (self) { + GRPCChannelRecord *record = _channelPool[configuration]; + NSAssert(record != nil, @"No record corresponding to a proxy."); + if (record == nil) return; + NSAssert(record.refcount > 0, @"Inconsistent channel refcount."); + if (record.refcount > 0) { + record.refcount--; + if (record.refcount == 0) { + NSDate *now = [NSDate date]; + record.timedDestroyDate = now; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_destroyDelay * NSEC_PER_SEC)), + _dispatchQueue, + ^{ + @synchronized (self) { + if (now == record.timedDestroyDate) { + // Destroy the raw channel and reset related records. + record.timedDestroyDate = nil; + record.refcount = 0; + record.channel = nil; + } + } + }); + } + } + } +} + +- (void)disconnectAllChannels { + NSMutableSet *proxySet = [NSMutableSet set]; + @synchronized (self) { + [_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannelRecord * _Nonnull obj, BOOL * _Nonnull stop) { + obj.channel = nil; + obj.timedDestroyDate = nil; + obj.refcount = 0; + [proxySet addObject:obj.proxy]; + }]; + } + // Disconnect proxies + [proxySet enumerateObjectsUsingBlock:^(GRPCPooledChannel * _Nonnull obj, BOOL * _Nonnull stop) { + [obj disconnect]; + }]; } - (void)connectivityChange:(NSNotification *)note { - [self destroyAllChannels]; + [self disconnectAllChannels]; } - (void)dealloc { diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index ae7f07f119..5c402250cc 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -238,7 +238,7 @@ @implementation GRPCWrappedCall { GRPCCompletionQueue *_queue; - GRPCChannel *_channel; + GRPCPooledChannel *_channel; grpc_call *_call; } @@ -257,21 +257,15 @@ // consuming too many threads and having contention of multiple calls in a single completion // queue. Currently we use a singleton queue. _queue = [GRPCCompletionQueue completionQueue]; - BOOL disconnected = NO; - do { - _channel = [[GRPCChannelPool sharedInstance] channelWithHost:host callOptions:callOptions]; - if (_channel == nil) { - NSAssert(_channel != nil, @"Failed to get a channel for the host."); - NSLog(@"Failed to get a channel for the host."); - return nil; - } - _call = [_channel unmanagedCallWithPath:path - completionQueue:_queue - callOptions:callOptions - disconnected:&disconnected]; - // Try create another channel if the current channel is disconnected (due to idleness or - // connectivity monitor disconnection). - } while (_call == NULL && disconnected); + _channel = [[GRPCChannelPool sharedInstance] channelWithHost:host callOptions:callOptions]; + if (_channel == nil) { + NSAssert(_channel != nil, @"Failed to get a channel for the host."); + NSLog(@"Failed to get a channel for the host."); + return nil; + } + _call = [_channel unmanagedCallWithPath:path + completionQueue:_queue + callOptions:callOptions]; if (_call == nil) { NSAssert(_channel != nil, @"Failed to get a channel for the host."); NSLog(@"Failed to create a call."); @@ -326,10 +320,7 @@ } - (void)dealloc { - if (_call) { - grpc_call_unref(_call); - } - [_channel unref]; + [_channel unrefUnmanagedCall:_call]; _channel = nil; } diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index b85e62feb5..51819b12c2 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -25,6 +25,8 @@ #define TEST_TIMEOUT 32 NSString *kDummyHost = @"dummy.host"; +NSString *kDummyHost2 = @"dummy.host.2"; +NSString *kDummyPath = @"/dummy/path"; @interface ChannelPoolTest : XCTestCase @@ -36,94 +38,156 @@ NSString *kDummyHost = @"dummy.host"; grpc_init(); } -- (void)testChannelPooling { - NSString *kDummyHost = @"dummy.host"; - NSString *kDummyHost2 = @"dummy.host2"; +- (void)testCreateChannelAndCall { + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options]; + XCTAssertNil(channel.wrappedChannel); + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + grpc_call *call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq callOptions:options]; + XCTAssert(call != NULL); + XCTAssertNotNil(channel.wrappedChannel); + [channel unrefUnmanagedCall:call]; + XCTAssertNil(channel.wrappedChannel); +} - GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init]; +- (void)testCacheChannel { + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCCallOptions *options1 = [[GRPCCallOptions alloc] init]; GRPCCallOptions *options2 = [options1 copy]; - GRPCMutableCallOptions *options3 = [options2 mutableCopy]; + GRPCMutableCallOptions *options3 = [options1 mutableCopy]; options3.transportType = GRPCTransportTypeInsecure; - - GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - - GRPCChannel *channel1 = [pool channelWithHost:kDummyHost callOptions:options1]; - GRPCChannel *channel2 = [pool channelWithHost:kDummyHost callOptions:options2]; - GRPCChannel *channel3 = [pool channelWithHost:kDummyHost2 callOptions:options1]; - GRPCChannel *channel4 = [pool channelWithHost:kDummyHost callOptions:options3]; - XCTAssertEqual(channel1, channel2); - XCTAssertNotEqual(channel1, channel3); - XCTAssertNotEqual(channel1, channel4); - XCTAssertNotEqual(channel3, channel4); -} - -- (void)testDestroyAllChannels { - NSString *kDummyHost = @"dummy.host"; - - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - GRPCChannel *channel = [pool channelWithHost:kDummyHost callOptions:options]; - grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:options - disconnected:nil]; - [pool destroyAllChannels]; - XCTAssertTrue(channel.disconnected); - GRPCChannel *channel2 = [pool channelWithHost:kDummyHost callOptions:options]; - XCTAssertNotEqual(channel, channel2); - grpc_call_unref(call); + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + GRPCPooledChannel *channel1 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options1]; + grpc_call *call1 = [channel1 unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options1]; + GRPCPooledChannel *channel2 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options2]; + grpc_call *call2 = [channel2 unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options2]; + GRPCPooledChannel *channel3 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options3]; + grpc_call *call3 = [channel3 unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options3]; + GRPCPooledChannel *channel4 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost2 + callOptions:options1]; + grpc_call *call4 = [channel4 unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options1]; + XCTAssertEqual(channel1.wrappedChannel, channel2.wrappedChannel); + XCTAssertNotEqual(channel1.wrappedChannel, channel3.wrappedChannel); + XCTAssertNotEqual(channel1.wrappedChannel, channel4.wrappedChannel); + XCTAssertNotEqual(channel3.wrappedChannel, channel4.wrappedChannel); + [channel1 unrefUnmanagedCall:call1]; + [channel2 unrefUnmanagedCall:call2]; + [channel3 unrefUnmanagedCall:call3]; + [channel4 unrefUnmanagedCall:call4]; } -- (void)testGetChannelBeforeChannelTimedDisconnection { - NSString *kDummyHost = @"dummy.host"; - const NSTimeInterval kDestroyDelay = 1; - - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - GRPCChannel *channel = - [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; - grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:options - disconnected:nil]; - grpc_call_unref(call); - [channel unref]; - - // Test that we can still get the channel at this time - GRPCChannel *channel2 = - [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; - XCTAssertEqual(channel, channel2); - call = [channel2 unmanagedCallWithPath:@"dummy.path" - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:options - disconnected:nil]; - - // Test that after the destroy delay, the channel is still alive +- (void)testTimedDestroyChannel { + const NSTimeInterval kDestroyDelay = 1.0; + + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + pool.destroyDelay = kDestroyDelay; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options]; + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + grpc_call *call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq callOptions:options]; + GRPCChannel *wrappedChannel = channel.wrappedChannel; + + [channel unrefUnmanagedCall:call]; + // Confirm channel is not destroyed at this time + call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertEqual(wrappedChannel, channel.wrappedChannel); + + [channel unrefUnmanagedCall:call]; sleep(kDestroyDelay + 1); - XCTAssertFalse(channel.disconnected); + // Confirm channel is new at this time + call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotEqual(wrappedChannel, channel.wrappedChannel); + + // Confirm the new channel can create call + call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssert(call != NULL); + [channel unrefUnmanagedCall:call]; } -- (void)testGetChannelAfterChannelTimedDisconnection { - NSString *kDummyHost = @"dummy.host"; - const NSTimeInterval kDestroyDelay = 1; - - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - GRPCChannelPool *pool = [GRPCChannelPool sharedInstance]; - GRPCChannel *channel = - [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; - grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:options - disconnected:nil]; - grpc_call_unref(call); - [channel unref]; - - sleep(kDestroyDelay + 1); +- (void)testPoolDisconnection { + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options]; + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + grpc_call *call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotNil(channel.wrappedChannel); + GRPCChannel *wrappedChannel = channel.wrappedChannel; + + // Test a new channel is created by requesting a channel from pool + [pool disconnectAllChannels]; + channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options]; + call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotNil(channel.wrappedChannel); + XCTAssertNotEqual(wrappedChannel, channel.wrappedChannel); + wrappedChannel = channel.wrappedChannel; + + // Test a new channel is created by requesting a new call from the previous proxy + [pool disconnectAllChannels]; + grpc_call *call2 = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotNil(channel.wrappedChannel); + XCTAssertNotEqual(channel.wrappedChannel, wrappedChannel); + [channel unrefUnmanagedCall:call]; + [channel unrefUnmanagedCall:call2]; +} - // Test that we get new channel to the same host and with the same callOptions - GRPCChannel *channel2 = - [pool channelWithHost:kDummyHost callOptions:options destroyDelay:kDestroyDelay]; - XCTAssertNotEqual(channel, channel2); +- (void)testUnrefCallFromStaleChannel { + GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options]; + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + grpc_call *call = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + + [pool disconnectAllChannels]; + channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost + callOptions:options]; + + grpc_call *call2 = [channel unmanagedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + // Test unref the call of a stale channel will not cause the current channel going into timed + // destroy state + XCTAssertNotNil(channel.wrappedChannel); + GRPCChannel *wrappedChannel = channel.wrappedChannel; + [channel unrefUnmanagedCall:call]; + XCTAssertNotNil(channel.wrappedChannel); + XCTAssertEqual(wrappedChannel, channel.wrappedChannel); + // Test unref the call of the current channel will cause the channel going into timed destroy + // state + [channel unrefUnmanagedCall:call2]; + XCTAssertNil(channel.wrappedChannel); } @end diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index 5daafcdf3f..212db2f653 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -20,65 +20,93 @@ #import "../../GRPCClient/GRPCCallOptions.h" #import "../../GRPCClient/private/GRPCChannel.h" +#import "../../GRPCClient/private/GRPCChannelPool.h" #import "../../GRPCClient/private/GRPCCompletionQueue.h" -@interface ChannelTests : XCTestCase +/* +#define TEST_TIMEOUT 8 + +@interface GRPCChannelFake : NSObject + +- (instancetype)initWithCreateExpectation:(XCTestExpectation *)createExpectation + unrefExpectation:(XCTestExpectation *)unrefExpectation; + +- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path + completionQueue:(GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions; + +- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall; @end -@implementation ChannelTests +@implementation GRPCChannelFake { + __weak XCTestExpectation *_createExpectation; + __weak XCTestExpectation *_unrefExpectation; + long _grpcCallCounter; +} -+ (void)setUp { - grpc_init(); +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { + return nil; } -- (void)testTimedDisconnection { - NSString *const kHost = @"grpc-test.sandbox.googleapis.com"; - const NSTimeInterval kDestroyDelay = 1; - GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCChannelConfiguration *configuration = - [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; - GRPCChannel *channel = - [[GRPCChannel alloc] initWithChannelConfiguration:configuration destroyDelay:kDestroyDelay]; - BOOL disconnected; - grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:options - disconnected:&disconnected]; - XCTAssertFalse(disconnected); - grpc_call_unref(call); - [channel unref]; - XCTAssertFalse(channel.disconnected, @"Channel is pre-maturely disconnected."); - sleep(kDestroyDelay + 1); - XCTAssertTrue(channel.disconnected, @"Channel is not disconnected after delay."); - - // Check another call creation returns null and indicates disconnected. - call = [channel unmanagedCallWithPath:@"dummy.path" - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:options - disconnected:&disconnected]; - XCTAssert(call == NULL); - XCTAssertTrue(disconnected); +- (instancetype)initWithCreateExpectation:(XCTestExpectation *)createExpectation + unrefExpectation:(XCTestExpectation *)unrefExpectation { + if ((self = [super init])) { + _createExpectation = createExpectation; + _unrefExpectation = unrefExpectation; + _grpcCallCounter = 0; + } + return self; } -- (void)testForceDisconnection { - NSString *const kHost = @"grpc-test.sandbox.googleapis.com"; - const NSTimeInterval kDestroyDelay = 1; - GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCChannelConfiguration *configuration = - [[GRPCChannelConfiguration alloc] initWithHost:kHost callOptions:options]; - GRPCChannel *channel = - [[GRPCChannel alloc] initWithChannelConfiguration:configuration destroyDelay:kDestroyDelay]; - grpc_call *call = [channel unmanagedCallWithPath:@"dummy.path" - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:options - disconnected:nil]; - grpc_call_unref(call); - [channel disconnect]; - XCTAssertTrue(channel.disconnected, @"Channel is not disconnected."); - - // Test calling another unref here will not crash - [channel unref]; +- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path + completionQueue:(GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions { + if (_createExpectation) [_createExpectation fulfill]; + return (grpc_call *)(++_grpcCallCounter); +} + +- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall { + if (_unrefExpectation) [_unrefExpectation fulfill]; +} + +@end + +@interface GRPCChannelPoolFake : NSObject + +- (instancetype)initWithDelayedDestroyExpectation:(XCTestExpectation *)delayedDestroyExpectation; + +- (GRPCChannel *)rawChannelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; + +- (void)delayedDestroyChannel; + +@end + +@implementation GRPCChannelPoolFake { + __weak XCTestExpectation *_delayedDestroyExpectation; +} + +- (instancetype)initWithDelayedDestroyExpectation:(XCTestExpectation *)delayedDestroyExpectation { + if ((self = [super init])) { + _delayedDestroyExpectation = delayedDestroyExpectation; + } + return self; +} + +- (void)delayedDestroyChannel { + if (_delayedDestroyExpectation) [_delayedDestroyExpectation fulfill]; +} + +@end */ + +@interface ChannelTests : XCTestCase + +@end + +@implementation ChannelTests + ++ (void)setUp { + grpc_init(); } @end -- cgit v1.2.3 From 680b53f7ad7c93947003dcf8d377f2b33c7623e9 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Sun, 18 Nov 2018 23:00:08 -0800 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.h | 4 +- src/objective-c/GRPCClient/GRPCCall.m | 59 ++++++------ src/objective-c/GRPCClient/private/GRPCChannel.h | 3 +- src/objective-c/GRPCClient/private/GRPCChannel.m | 18 ++-- .../GRPCClient/private/GRPCChannelPool.h | 4 +- .../GRPCClient/private/GRPCChannelPool.m | 58 ++++++------ .../GRPCClient/private/GRPCCronetChannelFactory.m | 6 +- src/objective-c/GRPCClient/private/GRPCHost.m | 3 +- .../private/GRPCInsecureChannelFactory.m | 3 +- .../GRPCClient/private/GRPCSecureChannelFactory.m | 15 ++- .../GRPCClient/private/GRPCWrappedCall.m | 7 +- src/objective-c/GRPCClient/private/utilities.h | 3 +- src/objective-c/ProtoRPC/ProtoRPC.m | 50 +++++----- .../tests/ChannelTests/ChannelPoolTest.m | 102 +++++++++------------ src/objective-c/tests/ChannelTests/ChannelTests.m | 4 +- src/objective-c/tests/InteropTests.m | 3 +- 16 files changed, 153 insertions(+), 189 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 7f80c17f1f..4c8c11eded 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -340,8 +340,8 @@ NS_ASSUME_NONNULL_END * and the port number, for example @"localhost:5050". */ - (null_unspecified instancetype)initWithHost:(null_unspecified NSString *)host - path:(null_unspecified NSString *)path - requestsWriter:(null_unspecified GRXWriter *)requestWriter; + path:(null_unspecified NSString *)path + requestsWriter:(null_unspecified GRXWriter *)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 6f4b1647a5..94e470d4ed 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -122,9 +122,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; responseHandler:(id)responseHandler callOptions:(GRPCCallOptions *)callOptions { NSAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0, - @"Neither host nor path can be nil."); - NSAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, - @"Invalid call safety value."); + @"Neither host nor path can be nil."); + NSAssert(requestOptions.safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); NSAssert(responseHandler != nil, @"Response handler required."); if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { return nil; @@ -136,7 +135,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; return nil; } - if ((self = [super init])) { _requestOptions = [requestOptions copy]; if (callOptions == nil) { @@ -159,7 +157,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; #endif _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } - dispatch_set_target_queue(_dispatchQueue ,responseHandler.dispatchQueue); + dispatch_set_target_queue(_dispatchQueue, responseHandler.dispatchQueue); _started = NO; _canceled = NO; _finished = NO; @@ -176,7 +174,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)start { GRPCCall *call = nil; - @synchronized (self) { + @synchronized(self) { NSAssert(!_started, @"Call already started."); NSAssert(!_canceled, @"Call already canceled."); if (_started) { @@ -192,10 +190,10 @@ const char *kCFStreamVarName = "grpc_cfstream"; } _call = [[GRPCCall alloc] initWithHost:_requestOptions.host - path:_requestOptions.path - callSafety:_requestOptions.safety - requestsWriter:_pipe - callOptions:_callOptions]; + path:_requestOptions.path + callSafety:_requestOptions.safety + requestsWriter:_pipe + callOptions:_callOptions]; if (_callOptions.initialMetadata) { [_call.requestHeaders addEntriesFromDictionary:_callOptions.initialMetadata]; } @@ -203,7 +201,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } void (^valueHandler)(id value) = ^(id value) { - @synchronized (self) { + @synchronized(self) { if (self->_handler) { if (!self->_initialMetadataPublished) { self->_initialMetadataPublished = YES; @@ -223,7 +221,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; [self issueInitialMetadata:self->_call.responseHeaders]; } [self issueClosedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil]; - } // Clearing _call must happen *after* dispatching close in order to get trailing // metadata from _call. @@ -237,14 +234,13 @@ const char *kCFStreamVarName = "grpc_cfstream"; } }; id responseWriteable = - [[GRXWriteable alloc] initWithValueHandler:valueHandler - completionHandler:completionHandler]; + [[GRXWriteable alloc] initWithValueHandler:valueHandler completionHandler:completionHandler]; [call startWithWriteable:responseWriteable]; } - (void)cancel { GRPCCall *call = nil; - @synchronized (self) { + @synchronized(self) { if (_canceled) { return; } @@ -259,7 +255,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; dispatch_async(_dispatchQueue, ^{ // Copy to local so that block is freed after cancellation completes. id copiedHandler = nil; - @synchronized (self) { + @synchronized(self) { copiedHandler = self->_handler; self->_handler = nil; } @@ -268,9 +264,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; error:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeCancelled userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; }); } } @@ -322,11 +318,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { - @synchronized (self) { - if (initialMetadata != nil && [_handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + @synchronized(self) { + if (initialMetadata != nil && + [_handler respondsToSelector:@selector(receivedInitialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ id handler = nil; - @synchronized (self) { + @synchronized(self) { handler = self->_handler; } [handler receivedInitialMetadata:initialMetadata]; @@ -336,11 +333,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueMessage:(id)message { - @synchronized (self) { + @synchronized(self) { if (message != nil && [_handler respondsToSelector:@selector(receivedRawMessage:)]) { dispatch_async(_dispatchQueue, ^{ id handler = nil; - @synchronized (self) { + @synchronized(self) { handler = self->_handler; } [handler receivedRawMessage:message]; @@ -350,17 +347,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - @synchronized (self) { + @synchronized(self) { if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ id handler = nil; - @synchronized (self) { + @synchronized(self) { handler = self->_handler; // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; } - [handler closedWithTrailingMetadata:trailingMetadata - error:error]; + [handler closedWithTrailingMetadata:trailingMetadata error:error]; }); } } @@ -489,10 +485,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; callOptions:(GRPCCallOptions *)callOptions { // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. NSAssert(host != nil && path != nil, @"Neither host nor path can be nil."); - NSAssert(safety <= GRPCCallSafetyCacheableRequest, - @"Invalid call safety value."); + NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); NSAssert(requestWriter.state == GRXWriterStateNotStarted, - @"The requests writer can't be already started."); + @"The requests writer can't be already started."); if (!host || !path) { return nil; } @@ -888,7 +883,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, - @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); + @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); if (_callOptions.authTokenProvider != nil) { @synchronized(self) { self.isWaitingForToken = YES; diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index de6d1bf4a2..5426b28d75 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -64,8 +64,7 @@ NS_ASSUME_NONNULL_BEGIN * Create a channel with remote \a host and signature \a channelConfigurations. */ - (nullable instancetype)initWithChannelConfiguration: - (GRPCChannelConfiguration *)channelConfiguration - NS_DESIGNATED_INITIALIZER; + (GRPCChannelConfiguration *)channelConfiguration NS_DESIGNATED_INITIALIZER; /** * Create a grpc core call object (grpc_call) from this channel. If no call is created, NULL is diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 81e53d48e3..e4cefc338c 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -178,10 +178,8 @@ grpc_channel *_unmanagedChannel; } -- (instancetype)initWithChannelConfiguration: - (GRPCChannelConfiguration *)channelConfiguration { - NSAssert(channelConfiguration != nil, - @"channelConfiguration must not be empty."); +- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { + NSAssert(channelConfiguration != nil, @"channelConfiguration must not be empty."); if (channelConfiguration == nil) return nil; if ((self = [super init])) { @@ -221,12 +219,11 @@ grpc_call *call = NULL; @synchronized(self) { - NSAssert(_unmanagedChannel != NULL, - @"Channel should have valid unmanaged channel."); + NSAssert(_unmanagedChannel != NULL, @"Channel should have valid unmanaged channel."); if (_unmanagedChannel == NULL) return NULL; NSString *serverAuthority = - callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; + callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; NSAssert(timeout >= 0, @"Invalid timeout"); if (timeout < 0) return NULL; @@ -236,10 +233,9 @@ } grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); gpr_timespec deadline_ms = - timeout == 0 - ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); call = grpc_channel_create_call(_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, serverAuthority ? &host_slice : NULL, deadline_ms, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 887bd5f89f..1e3c1d7d97 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -42,10 +42,10 @@ NS_ASSUME_NONNULL_BEGIN /** * Initialize with an actual channel object \a channel and a reference to the channel pool. */ -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration +- (nullable instancetype)initWithChannelConfiguration: + (GRPCChannelConfiguration *)channelConfiguration channelPool:(GRPCChannelPool *)channelPool; - /** * Create a grpc core call object (grpc_call) from this channel. If channel is disconnected, get a * new channel object from the channel pool. diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 92dd4c86ae..7c139b3717 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -40,7 +40,7 @@ static dispatch_once_t gInitChannelPool; /** When all calls of a channel are destroyed, destroy the channel after this much seconds. */ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; -@interface GRPCChannelPool() +@interface GRPCChannelPool () - (GRPCChannel *)refChannelWithConfiguration:(GRPCChannelConfiguration *)configuration; @@ -74,7 +74,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } - (grpc_call *)unmanagedCallWithPath:(NSString *)path - completionQueue:(GRPCCompletionQueue *)queue + completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions { NSAssert(path.length > 0, @"path must not be empty."); NSAssert(queue != nil, @"completionQueue must not be empty."); @@ -90,7 +90,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } NSAssert(_wrappedChannel != nil, @"Unable to get a raw channel for proxy."); } - call = [_wrappedChannel unmanagedCallWithPath:path completionQueue:queue callOptions:callOptions]; + call = + [_wrappedChannel unmanagedCallWithPath:path completionQueue:queue callOptions:callOptions]; if (call != NULL) { [_unmanagedCalls addObject:[NSValue valueWithPointer:call]]; } @@ -100,7 +101,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall { if (unmanagedCall == nil) return; - + grpc_call_unref(unmanagedCall); BOOL timedDestroy = NO; @synchronized(self) { @@ -125,7 +126,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (GRPCChannel *)wrappedChannel { GRPCChannel *channel = nil; - @synchronized (self) { + @synchronized(self) { channel = _wrappedChannel; } return channel; @@ -148,7 +149,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; /** * A convenience value type for cached channel. */ -@interface GRPCChannelRecord : NSObject +@interface GRPCChannelRecord : NSObject /** Pointer to the raw channel. May be nil when the channel has been destroyed. */ @property GRPCChannel *channel; @@ -197,14 +198,14 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 if (@available(iOS 8.0, macOS 10.10, *)) { _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { #else - { + { #endif - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } _destroyDelay = kDefaultChannelDestroyDelay; // Connectivity monitor is not required for CFStream @@ -221,7 +222,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; NSAssert(callOptions != nil, @"callOptions must not be empty."); if (host.length == 0) return nil; if (callOptions == nil) return nil; - + GRPCPooledChannel *channelProxy = nil; GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; @@ -229,8 +230,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; GRPCChannelRecord *record = _channelPool[configuration]; if (record == nil) { record = [[GRPCChannelRecord alloc] init]; - record.proxy = [[GRPCPooledChannel alloc] initWithChannelConfiguration:configuration - channelPool:self]; + record.proxy = + [[GRPCPooledChannel alloc] initWithChannelConfiguration:configuration channelPool:self]; record.timedDestroyDate = nil; _channelPool[configuration] = record; channelProxy = record.proxy; @@ -247,7 +248,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (GRPCChannel *)refChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { GRPCChannel *ret = nil; - @synchronized (self) { + @synchronized(self) { NSAssert(configuration != nil, @"configuration cannot be empty."); if (configuration == nil) return nil; @@ -271,7 +272,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } - (void)unrefChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { - @synchronized (self) { + @synchronized(self) { GRPCChannelRecord *record = _channelPool[configuration]; NSAssert(record != nil, @"No record corresponding to a proxy."); if (record == nil) return; @@ -282,9 +283,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; NSDate *now = [NSDate date]; record.timedDestroyDate = now; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_destroyDelay * NSEC_PER_SEC)), - _dispatchQueue, - ^{ - @synchronized (self) { + _dispatchQueue, ^{ + @synchronized(self) { if (now == record.timedDestroyDate) { // Destroy the raw channel and reset related records. record.timedDestroyDate = nil; @@ -292,7 +292,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; record.channel = nil; } } - }); + }); } } } @@ -300,16 +300,18 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (void)disconnectAllChannels { NSMutableSet *proxySet = [NSMutableSet set]; - @synchronized (self) { - [_channelPool enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration * _Nonnull key, GRPCChannelRecord * _Nonnull obj, BOOL * _Nonnull stop) { - obj.channel = nil; - obj.timedDestroyDate = nil; - obj.refcount = 0; - [proxySet addObject:obj.proxy]; - }]; + @synchronized(self) { + [_channelPool + enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration *_Nonnull key, + GRPCChannelRecord *_Nonnull obj, BOOL *_Nonnull stop) { + obj.channel = nil; + obj.timedDestroyDate = nil; + obj.refcount = 0; + [proxySet addObject:obj.proxy]; + }]; } // Disconnect proxies - [proxySet enumerateObjectsUsingBlock:^(GRPCPooledChannel * _Nonnull obj, BOOL * _Nonnull stop) { + [proxySet enumerateObjectsUsingBlock:^(GRPCPooledChannel *_Nonnull obj, BOOL *_Nonnull stop) { [obj disconnect]; }]; } diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index 74ea9723b3..0aeb67b142 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -50,8 +50,7 @@ return self; } -- (grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { grpc_channel_args *channelArgs = GRPCBuildChannelArgs(args); grpc_channel *unmanagedChannel = grpc_cronet_secure_channel_create(_cronetEngine, host.UTF8String, channelArgs, NULL); @@ -71,8 +70,7 @@ return nil; } -- (grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { [NSException raise:NSInvalidArgumentException format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; return NULL; diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index b693b926ba..0f2281ede8 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -122,8 +122,7 @@ static NSMutableDictionary *gHostCache; if (_transportType == GRPCTransportTypeInsecure) { options.transportType = GRPCTransportTypeInsecure; } else { - NSAssert(_transportType == GRPCTransportTypeDefault, - @"Invalid transport type"); + NSAssert(_transportType == GRPCTransportTypeDefault, @"Invalid transport type"); options.transportType = GRPCTransportTypeCronet; } } else diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m index 3e9ebe7ae0..b802137c13 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -32,8 +32,7 @@ return instance; } -- (grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 2e7f1a0dbe..69f70de17d 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -29,9 +29,9 @@ } + (instancetype)factoryWithPEMRootCertificates:(NSString *)rootCerts - privateKey:(NSString *)privateKey - certChain:(NSString *)certChain - error:(NSError **)errorPtr { + privateKey:(NSString *)privateKey + certChain:(NSString *)certChain + error:(NSError **)errorPtr { return [[self alloc] initWithPEMRootCerts:rootCerts privateKey:privateKey certChain:certChain @@ -50,9 +50,9 @@ } - (instancetype)initWithPEMRootCerts:(NSString *)rootCerts - privateKey:(NSString *)privateKey - certChain:(NSString *)certChain - error:(NSError **)errorPtr { + privateKey:(NSString *)privateKey + certChain:(NSString *)certChain + error:(NSError **)errorPtr { static NSData *defaultRootsASCII; static NSError *defaultRootsError; static dispatch_once_t loading; @@ -115,8 +115,7 @@ return self; } -- (grpc_channel *)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *)args { +- (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 5c402250cc..615dfc8556 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -249,8 +249,7 @@ - (instancetype)initWithHost:(NSString *)host path:(NSString *)path callOptions:(GRPCCallOptions *)callOptions { - NSAssert(host.length != 0 && path.length != 0, - @"path and host cannot be nil."); + NSAssert(host.length != 0 && path.length != 0, @"path and host cannot be nil."); if ((self = [super init])) { // Each completion queue consumes one thread. There's a trade to be made between creating and @@ -263,9 +262,7 @@ NSLog(@"Failed to get a channel for the host."); return nil; } - _call = [_channel unmanagedCallWithPath:path - completionQueue:_queue - callOptions:callOptions]; + _call = [_channel unmanagedCallWithPath:path completionQueue:_queue callOptions:callOptions]; if (_call == nil) { NSAssert(_channel != nil, @"Failed to get a channel for the host."); NSLog(@"Failed to create a call."); diff --git a/src/objective-c/GRPCClient/private/utilities.h b/src/objective-c/GRPCClient/private/utilities.h index 8f6baadcf7..8e3dd79358 100644 --- a/src/objective-c/GRPCClient/private/utilities.h +++ b/src/objective-c/GRPCClient/private/utilities.h @@ -19,5 +19,4 @@ #import /** Raise exception when condition not met. */ -#define GRPCAssert(condition, errorString) \ - NSAssert(condition, errorString) +#define GRPCAssert(condition, errorString) NSAssert(condition, errorString) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 9164f2320b..2de2932072 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -138,21 +138,21 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing call = _call; _call = nil; if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { - dispatch_async(_handler.dispatchQueue, ^{ - id handler = nil; - @synchronized(self) { - handler = self->_handler; - self->_handler = nil; - } - [handler closedWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; - }); - } + dispatch_async(_handler.dispatchQueue, ^{ + id handler = nil; + @synchronized(self) { + handler = self->_handler; + self->_handler = nil; + } + [handler closedWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + }); + } } [call cancel]; } @@ -179,11 +179,11 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { - @synchronized (self) { + @synchronized(self) { if (initialMetadata != nil && [_handler respondsToSelector:@selector(initialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ id handler = nil; - @synchronized (self) { + @synchronized(self) { handler = self->_handler; } [handler receivedInitialMetadata:initialMetadata]; @@ -197,19 +197,20 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing NSError *error = nil; GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; - @synchronized (self) { + @synchronized(self) { if (parsed && [_handler respondsToSelector:@selector(receivedProtoMessage:)]) { dispatch_async(_dispatchQueue, ^{ id handler = nil; - @synchronized (self) { + @synchronized(self) { handler = self->_handler; } [handler receivedProtoMessage:parsed]; }); - } else if (!parsed && [_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]){ + } else if (!parsed && + [_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ id handler = nil; - @synchronized (self) { + @synchronized(self) { handler = self->_handler; self->_handler = nil; } @@ -222,13 +223,12 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata - error:(NSError *)error { - @synchronized (self) { +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { + @synchronized(self) { if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ id handler = nil; - @synchronized (self) { + @synchronized(self) { handler = self->_handler; self->_handler = nil; } diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index 51819b12c2..4424801c11 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -41,12 +41,12 @@ NSString *kDummyPath = @"/dummy/path"; - (void)testCreateChannelAndCall { GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options]; + GRPCPooledChannel *channel = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; XCTAssertNil(channel.wrappedChannel); GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq callOptions:options]; + grpc_call *call = + [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssert(call != NULL); XCTAssertNotNil(channel.wrappedChannel); [channel unrefUnmanagedCall:call]; @@ -60,26 +60,22 @@ NSString *kDummyPath = @"/dummy/path"; GRPCMutableCallOptions *options3 = [options1 mutableCopy]; options3.transportType = GRPCTransportTypeInsecure; GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - GRPCPooledChannel *channel1 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options1]; - grpc_call *call1 = [channel1 unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options1]; - GRPCPooledChannel *channel2 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options2]; - grpc_call *call2 = [channel2 unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options2]; - GRPCPooledChannel *channel3 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options3]; - grpc_call *call3 = [channel3 unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options3]; - GRPCPooledChannel *channel4 = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost2 - callOptions:options1]; - grpc_call *call4 = [channel4 unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options1]; + GRPCPooledChannel *channel1 = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options1]; + grpc_call *call1 = + [channel1 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options1]; + GRPCPooledChannel *channel2 = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options2]; + grpc_call *call2 = + [channel2 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options2]; + GRPCPooledChannel *channel3 = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options3]; + grpc_call *call3 = + [channel3 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options3]; + GRPCPooledChannel *channel4 = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost2 callOptions:options1]; + grpc_call *call4 = + [channel4 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options1]; XCTAssertEqual(channel1.wrappedChannel, channel2.wrappedChannel); XCTAssertNotEqual(channel1.wrappedChannel, channel3.wrappedChannel); XCTAssertNotEqual(channel1.wrappedChannel, channel4.wrappedChannel); @@ -96,32 +92,26 @@ NSString *kDummyPath = @"/dummy/path"; GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; pool.destroyDelay = kDestroyDelay; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options]; + GRPCPooledChannel *channel = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq callOptions:options]; + grpc_call *call = + [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; GRPCChannel *wrappedChannel = channel.wrappedChannel; [channel unrefUnmanagedCall:call]; // Confirm channel is not destroyed at this time - call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertEqual(wrappedChannel, channel.wrappedChannel); [channel unrefUnmanagedCall:call]; sleep(kDestroyDelay + 1); // Confirm channel is new at this time - call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotEqual(wrappedChannel, channel.wrappedChannel); // Confirm the new channel can create call - call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssert(call != NULL); [channel unrefUnmanagedCall:call]; } @@ -129,31 +119,26 @@ NSString *kDummyPath = @"/dummy/path"; - (void)testPoolDisconnection { GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options]; + GRPCPooledChannel *channel = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + grpc_call *call = + [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); GRPCChannel *wrappedChannel = channel.wrappedChannel; // Test a new channel is created by requesting a channel from pool [pool disconnectAllChannels]; - channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options]; - call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; + call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); XCTAssertNotEqual(wrappedChannel, channel.wrappedChannel); wrappedChannel = channel.wrappedChannel; // Test a new channel is created by requesting a new call from the previous proxy [pool disconnectAllChannels]; - grpc_call *call2 = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + grpc_call *call2 = + [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); XCTAssertNotEqual(channel.wrappedChannel, wrappedChannel); [channel unrefUnmanagedCall:call]; @@ -163,20 +148,17 @@ NSString *kDummyPath = @"/dummy/path"; - (void)testUnrefCallFromStaleChannel { GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options]; + GRPCPooledChannel *channel = + (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + grpc_call *call = + [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; [pool disconnectAllChannels]; - channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost - callOptions:options]; + channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; - grpc_call *call2 = [channel unmanagedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + grpc_call *call2 = + [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; // Test unref the call of a stale channel will not cause the current channel going into timed // destroy state XCTAssertNotNil(channel.wrappedChannel); diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index 212db2f653..c07c8e6983 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -45,8 +45,8 @@ long _grpcCallCounter; } -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { - return nil; +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration +*)channelConfiguration { return nil; } - (instancetype)initWithCreateExpectation:(XCTestExpectation *)createExpectation diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 8754bd5cca..a9f33aab6f 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -114,8 +114,7 @@ BOOL isRemoteInteropTest(NSString *host) { } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata - error:(NSError *)error { +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { if (_closeCallback) { _closeCallback(trailingMetadata, error); } -- cgit v1.2.3 From 00ff5805a3c00e9d29cb71dfd5365c36dd5bf96c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 09:43:24 -0800 Subject: null_unspecified -> nullable --- src/objective-c/GRPCClient/GRPCCall.h | 26 +++++++++++++------------- src/objective-c/ProtoRPC/ProtoRPC.h | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 4c8c11eded..214969af23 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -306,7 +306,7 @@ NS_ASSUME_NONNULL_END * * The property is initialized to an empty NSMutableDictionary. */ -@property(null_unspecified, atomic, readonly) NSMutableDictionary *requestHeaders; +@property(nullable, atomic, readonly) NSMutableDictionary *requestHeaders; /** * This dictionary is populated with the HTTP headers received from the server. This happens before @@ -317,7 +317,7 @@ NS_ASSUME_NONNULL_END * The value of this property is nil until all response headers are received, and will change before * any of -writeValue: or -writesFinishedWithError: are sent to the writeable. */ -@property(null_unspecified, atomic, readonly) NSDictionary *responseHeaders; +@property(nullable, atomic, readonly) NSDictionary *responseHeaders; /** * Same as responseHeaders, but populated with the HTTP trailers received from the server before the @@ -326,7 +326,7 @@ NS_ASSUME_NONNULL_END * The value of this property is nil until all response trailers are received, and will change * before -writesFinishedWithError: is sent to the writeable. */ -@property(null_unspecified, atomic, readonly) NSDictionary *responseTrailers; +@property(nullable, atomic, readonly) NSDictionary *responseTrailers; /** * The request writer has to write NSData objects into the provided Writeable. The server will @@ -339,9 +339,9 @@ NS_ASSUME_NONNULL_END * host parameter should not contain the scheme (http:// or https://), only the name or IP addr * and the port number, for example @"localhost:5050". */ -- (null_unspecified instancetype)initWithHost:(null_unspecified NSString *)host - path:(null_unspecified NSString *)path - requestsWriter:(null_unspecified GRXWriter *)requestWriter; +- (nullable instancetype)initWithHost:(nullable NSString *)host + path:(nullable NSString *)path + requestsWriter:(nullable GRXWriter *)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and @@ -353,11 +353,11 @@ NS_ASSUME_NONNULL_END * The following methods are deprecated. */ + (void)setCallSafety:(GRPCCallSafety)callSafety - host:(null_unspecified NSString *)host - path:(null_unspecified NSString *)path; -@property(null_unspecified, atomic, copy, readwrite) NSString *serverName; + host:(nullable NSString *)host + path:(nullable NSString *)path; +@property(nullable, atomic, copy, readwrite) NSString *serverName; @property NSTimeInterval timeout; -- (void)setResponseDispatchQueue:(null_unspecified dispatch_queue_t)queue; +- (void)setResponseDispatchQueue:(nullable dispatch_queue_t)queue; @end @@ -368,11 +368,11 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; -- (null_unspecified id)objectForKeyedSubscript:(null_unspecified id)key; -- (void)setObject:(null_unspecified id)obj forKeyedSubscript:(null_unspecified id)key; +- (nullable id)objectForKeyedSubscript:(nullable id)key; +- (void)setObject:(nullable id)obj forKeyedSubscript:(nullable id)key; - (void)removeAllObjects; -- (void)removeObjectForKey:(null_unspecified id)key; +- (void)removeObjectForKey:(nullable id)key; @end #pragma clang diagnostic push diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 98b60c3f72..2623aecb82 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -132,11 +132,11 @@ __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC * addr and the port number, for example @"localhost:5050". */ - - (instancetype _Null_unspecified)initWithHost : (NSString *_Null_unspecified)host method - : (GRPCProtoMethod *_Null_unspecified)method requestsWriter - : (GRXWriter *_Null_unspecified)requestsWriter responseClass - : (Class _Null_unspecified)responseClass responsesWriteable - : (id _Null_unspecified)responsesWriteable NS_DESIGNATED_INITIALIZER; + (nullable instancetype)initWithHost : (nullable NSString *)host method + : (nullable GRPCProtoMethod *)method requestsWriter + : (nullable GRXWriter *)requestsWriter responseClass + : (nullable Class)responseClass responsesWriteable + : (nullable id)responsesWriteable NS_DESIGNATED_INITIALIZER; - (void)start; @end -- cgit v1.2.3 From 29e1591904539fcb6d92ba49e69ed27ee9d3349d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 09:52:29 -0800 Subject: _Nullable -> nullable --- .../GRPCClient/private/GRPCCronetChannelFactory.h | 8 ++++---- .../GRPCClient/private/GRPCInsecureChannelFactory.h | 8 ++++---- .../GRPCClient/private/GRPCSecureChannelFactory.h | 12 ++++++------ src/objective-c/tests/APIv2Tests/APIv2Tests.m | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h index 5e35576ea1..738dfdb737 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h @@ -24,12 +24,12 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCCronetChannelFactory : NSObject -+ (instancetype _Nullable)sharedInstance; ++ (nullable instancetype)sharedInstance; -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args; +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSDictionary *)args; -- (instancetype _Nullable)init NS_UNAVAILABLE; +- (nullable instancetype)init NS_UNAVAILABLE; @end diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h index 98a985fe84..2d471aebed 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h @@ -23,12 +23,12 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCInsecureChannelFactory : NSObject -+ (instancetype _Nullable)sharedInstance; ++ (nullable instancetype)sharedInstance; -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args; +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSDictionary *)args; -- (instancetype _Nullable)init NS_UNAVAILABLE; +- (nullable instancetype)init NS_UNAVAILABLE; @end diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h index 02e7052996..5dc5a97312 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h @@ -23,15 +23,15 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCSecureChannelFactory : NSObject -+ (instancetype _Nullable)factoryWithPEMRootCertificates:(NSString *_Nullable)rootCerts - privateKey:(NSString *_Nullable)privateKey - certChain:(NSString *_Nullable)certChain ++ (nullable instancetype)factoryWithPEMRootCertificates:(nullable NSString *)rootCerts + privateKey:(nullable NSString *)privateKey + certChain:(nullable NSString *)certChain error:(NSError **)errorPtr; -- (grpc_channel *_Nullable)createChannelWithHost:(NSString *)host - channelArgs:(NSDictionary *_Nullable)args; +- (nullable grpc_channel *)createChannelWithHost:(NSString *)host + channelArgs:(nullable NSDictionary *)args; -- (instancetype _Nullable)init NS_UNAVAILABLE; +- (nullable instancetype)init NS_UNAVAILABLE; @end diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index e49f58ae9d..1b14043af9 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -81,20 +81,20 @@ static const NSTimeInterval kTestTimeout = 16; return self; } -- (void)receivedInitialMetadata:(NSDictionary *_Nullable)initialMetadata { +- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { if (self->_initialMetadataCallback) { self->_initialMetadataCallback(initialMetadata); } } -- (void)receivedRawMessage:(GPBMessage *_Nullable)message { +- (void)receivedRawMessage:(GPBMessage *)message { if (self->_messageCallback) { self->_messageCallback(message); } } -- (void)closedWithTrailingMetadata:(NSDictionary *_Nullable)trailingMetadata - error:(NSError *_Nullable)error { +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata + error:(NSError *)error { if (self->_closeCallback) { self->_closeCallback(trailingMetadata, error); } -- cgit v1.2.3 From d806ce71d762a1a2fc03e41cc186d002ee604316 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 10:08:23 -0800 Subject: more nullability --- src/objective-c/GRPCClient/GRPCCallOptions.h | 2 +- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h | 6 +++--- src/objective-c/tests/APIv2Tests/APIv2Tests.m | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 61d8564286..e88e28109c 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -64,7 +64,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ -- (void)getTokenWithHandler:(void (^)(NSString *token))handler; +- (void)getTokenWithHandler:(void (^)(NSString * _Nullable token))handler; @end @interface GRPCCallOptions : NSObject diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h index 5dc5a97312..588239b706 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h @@ -24,9 +24,9 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCSecureChannelFactory : NSObject + (nullable instancetype)factoryWithPEMRootCertificates:(nullable NSString *)rootCerts - privateKey:(nullable NSString *)privateKey - certChain:(nullable NSString *)certChain - error:(NSError **)errorPtr; + privateKey:(nullable NSString *)privateKey + certChain:(nullable NSString *)certChain + error:(NSError **)errorPtr; - (nullable grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(nullable NSDictionary *)args; diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index 1b14043af9..32f2122f79 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -93,8 +93,7 @@ static const NSTimeInterval kTestTimeout = 16; } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata - error:(NSError *)error { +- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { if (self->_closeCallback) { self->_closeCallback(trailingMetadata, error); } -- cgit v1.2.3 From 1d8550c4c27ca357195946759f161942a6e07589 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 19 Nov 2018 11:26:24 -0800 Subject: nit nullability fix --- src/objective-c/GRPCClient/GRPCCallOptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index e88e28109c..48bb11aeeb 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -64,7 +64,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ -- (void)getTokenWithHandler:(void (^)(NSString * _Nullable token))handler; +- (void)getTokenWithHandler:(void (^ _Nullable)(NSString * _Nullable token))handler; @end @interface GRPCCallOptions : NSObject -- cgit v1.2.3 From f62323aea28260d4233487dc84834dd26c48845c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 20 Nov 2018 13:21:07 -0800 Subject: Tests project fixes --- src/objective-c/tests/Tests.xcodeproj/project.pbxproj | 8 -------- .../Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme | 7 +++++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index 6d1932b021..6f24d3512f 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -1276,15 +1276,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-APIv2Tests-checkManifestLockResult.txt", ); @@ -1856,15 +1852,11 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - ); outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme index 16ae481123..8c8623d7b2 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme @@ -26,7 +26,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -47,7 +51,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" -- cgit v1.2.3 From 03c73e92f1dedb1de4bba0269e7c614b47cf8035 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 21 Nov 2018 15:31:10 -0800 Subject: Fix test failure due to NSAssert --- src/objective-c/tests/Podfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index 5df9d4e85b..12112f95e1 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -148,5 +148,14 @@ post_install do |installer| end end end + + # Enable NSAssert on gRPC + if target.name == 'gRPC' || target.name == 'ProtoRPC' || target.name == 'RxLibrary' + target.build_configurations.each do |config| + if config.name != 'Release' + config.build_settings['ENABLE_NS_ASSERTIONS'] = 'YES' + end + end + end end end -- cgit v1.2.3 From 5ae61f5a5a267f5975248d4262133a740e09a66b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 26 Nov 2018 17:17:09 -0800 Subject: Multiple fixes --- src/objective-c/GRPCClient/GRPCCall+ChannelArg.m | 2 +- src/objective-c/GRPCClient/GRPCCall.m | 53 ++++---- .../GRPCClient/private/ChannelArgsUtil.m | 21 ++- src/objective-c/GRPCClient/private/GRPCChannel.h | 6 +- src/objective-c/GRPCClient/private/GRPCChannel.m | 66 +++++----- .../GRPCClient/private/GRPCChannelPool.h | 49 +++---- .../GRPCClient/private/GRPCChannelPool.m | 145 +++++++++++---------- .../GRPCClient/private/GRPCWrappedCall.m | 2 +- src/objective-c/ProtoRPC/ProtoRPC.m | 38 +++--- .../tests/ChannelTests/ChannelPoolTest.m | 40 +++--- src/objective-c/tests/ChannelTests/ChannelTests.m | 4 +- src/objective-c/tests/GRPCClientTests.m | 7 +- 12 files changed, 221 insertions(+), 212 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m index 703cff63bb..ae60d6208e 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m @@ -36,7 +36,7 @@ } + (void)closeOpenConnections { - [[GRPCChannelPool sharedInstance] closeOpenConnections]; + [[GRPCChannelPool sharedInstance] disconnectAllChannels]; } + (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm forhost:(nonnull NSString *)host { diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 94e470d4ed..bf9441c27e 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -69,11 +69,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { NSAssert(host.length != 0 && path.length != 0, @"Host and Path cannot be empty"); - if (host.length == 0) { - host = [NSString string]; - } - if (path.length == 0) { - path = [NSString string]; + if (host.length == 0 || path.length == 0) { + return nil; } if ((self = [super init])) { _host = [host copy]; @@ -173,7 +170,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; } - (void)start { - GRPCCall *call = nil; + GRPCCall *copiedCall = nil; @synchronized(self) { NSAssert(!_started, @"Call already started."); NSAssert(!_canceled, @"Call already canceled."); @@ -197,7 +194,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (_callOptions.initialMetadata) { [_call.requestHeaders addEntriesFromDictionary:_callOptions.initialMetadata]; } - call = _call; + copiedCall = _call; } void (^valueHandler)(id value) = ^(id value) { @@ -235,11 +232,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; }; id responseWriteable = [[GRXWriteable alloc] initWithValueHandler:valueHandler completionHandler:completionHandler]; - [call startWithWriteable:responseWriteable]; + [copiedCall startWithWriteable:responseWriteable]; } - (void)cancel { - GRPCCall *call = nil; + GRPCCall *copiedCall = nil; @synchronized(self) { if (_canceled) { return; @@ -247,7 +244,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; _canceled = YES; - call = _call; + copiedCall = _call; _call = nil; _pipe = nil; @@ -268,13 +265,15 @@ const char *kCFStreamVarName = "grpc_cfstream"; @"Canceled by app" }]]; }); + } else { + _handler = nil; } } - [call cancel]; + [copiedCall cancel]; } - (void)writeData:(NSData *)data { - GRXBufferedPipe *pipe = nil; + GRXBufferedPipe *copiedPipe = nil; @synchronized(self) { NSAssert(!_canceled, @"Call arleady canceled."); NSAssert(!_finished, @"Call is half-closed before sending data."); @@ -286,14 +285,14 @@ const char *kCFStreamVarName = "grpc_cfstream"; } if (_pipe) { - pipe = _pipe; + copiedPipe = _pipe; } } - [pipe writeValue:data]; + [copiedPipe writeValue:data]; } - (void)finish { - GRXBufferedPipe *pipe = nil; + GRXBufferedPipe *copiedPipe = nil; @synchronized(self) { NSAssert(_started, @"Call not started."); NSAssert(!_canceled, @"Call arleady canceled."); @@ -309,12 +308,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; } if (_pipe) { - pipe = _pipe; + copiedPipe = _pipe; _pipe = nil; } _finished = YES; } - [pipe writesFinishedWithError:nil]; + [copiedPipe writesFinishedWithError:nil]; } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { @@ -322,11 +321,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; if (initialMetadata != nil && [_handler respondsToSelector:@selector(receivedInitialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; } - [handler receivedInitialMetadata:initialMetadata]; + [copiedHandler receivedInitialMetadata:initialMetadata]; }); } } @@ -336,11 +335,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; @synchronized(self) { if (message != nil && [_handler respondsToSelector:@selector(receivedRawMessage:)]) { dispatch_async(_dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; } - [handler receivedRawMessage:message]; + [copiedHandler receivedRawMessage:message]; }); } } @@ -350,14 +349,16 @@ const char *kCFStreamVarName = "grpc_cfstream"; @synchronized(self) { if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; } - [handler closedWithTrailingMetadata:trailingMetadata error:error]; + [copiedHandler closedWithTrailingMetadata:trailingMetadata error:error]; }); + } else { + _handler = nil; } } } diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m index d9e44b557d..3135fcff02 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -60,36 +60,35 @@ grpc_channel_args *GRPCBuildChannelArgs(NSDictionary *dictionary) { 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 + NSUInteger j = 0; for (NSUInteger i = 0; i < argCount; ++i) { - grpc_arg *arg = &channelArgs->args[i]; + grpc_arg *arg = &channelArgs->args[j]; 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]); + j++; } else if ([value respondsToSelector:@selector(intValue)]) { - if ([value compare:[NSNumber numberWithInteger:INT_MAX]] == NSOrderedDescending || - [value compare:[NSNumber numberWithInteger:INT_MIN]] == NSOrderedAscending) { - [NSException raise:NSInvalidArgumentException - format:@"Out of range for a value-typed channel argument: %@", value]; + int64_t value64 = [value longLongValue]; + if (value64 <= INT_MAX || value64 >= INT_MIN) { + arg->type = GRPC_ARG_INTEGER; + arg->value.integer = [value intValue]; + j++; } - arg->type = GRPC_ARG_INTEGER; - arg->value.integer = [value intValue]; } else if (value != nil) { arg->type = GRPC_ARG_POINTER; arg->value.pointer.p = (__bridge_retained void *)value; arg->value.pointer.vtable = &objc_arg_vtable; - } else { - [NSException raise:NSInvalidArgumentException - format:@"Invalid channel argument type: %@", [value class]]; + j++; } } + channelArgs->num_args = j; return channelArgs; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 5426b28d75..147015bed1 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -32,6 +32,10 @@ NS_ASSUME_NONNULL_BEGIN /** Caching signature of a channel. */ @interface GRPCChannelConfiguration : NSObject +- (instancetype)init NS_UNAVAILABLE; + ++ (instancetype) new NS_UNAVAILABLE; + /** The host that this channel is connected to. */ @property(copy, readonly) NSString *host; @@ -47,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN /** Acquire the dictionary of channel args with current configurations. */ @property(copy, readonly) NSDictionary *channelArgs; -- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; +- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index e4cefc338c..24cf670d1b 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -39,8 +39,9 @@ - (instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { NSAssert(host.length > 0, @"Host must not be empty."); NSAssert(callOptions != nil, @"callOptions must not be empty."); - if (host.length == 0) return nil; - if (callOptions == nil) return nil; + if (host.length == 0 || callOptions == nil) { + return nil; + } if ((self = [super init])) { _host = [host copy]; @@ -180,7 +181,9 @@ - (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { NSAssert(channelConfiguration != nil, @"channelConfiguration must not be empty."); - if (channelConfiguration == nil) return nil; + if (channelConfiguration == nil) { + return nil; + } if ((self = [super init])) { _configuration = [channelConfiguration copy]; @@ -218,35 +221,34 @@ if (callOptions == nil) return NULL; grpc_call *call = NULL; - @synchronized(self) { - NSAssert(_unmanagedChannel != NULL, @"Channel should have valid unmanaged channel."); - if (_unmanagedChannel == NULL) return NULL; - - NSString *serverAuthority = - callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; - NSTimeInterval timeout = callOptions.timeout; - NSAssert(timeout >= 0, @"Invalid timeout"); - if (timeout < 0) return NULL; - grpc_slice host_slice = grpc_empty_slice(); - if (serverAuthority) { - host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); - } - grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); - gpr_timespec deadline_ms = - timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); - call = grpc_channel_create_call(_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, - queue.unmanagedQueue, path_slice, - serverAuthority ? &host_slice : NULL, deadline_ms, NULL); - if (serverAuthority) { - grpc_slice_unref(host_slice); - } - grpc_slice_unref(path_slice); - NSAssert(call != nil, @"Unable to create call."); - if (call == NULL) { - NSLog(@"Unable to create call."); - } + // No need to lock here since _unmanagedChannel is only changed in _dealloc + NSAssert(_unmanagedChannel != NULL, @"Channel should have valid unmanaged channel."); + if (_unmanagedChannel == NULL) return NULL; + + NSString *serverAuthority = + callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; + NSTimeInterval timeout = callOptions.timeout; + NSAssert(timeout >= 0, @"Invalid timeout"); + if (timeout < 0) return NULL; + grpc_slice host_slice = grpc_empty_slice(); + if (serverAuthority) { + host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); + } + grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); + gpr_timespec deadline_ms = + timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + call = grpc_channel_create_call(_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, + queue.unmanagedQueue, path_slice, + serverAuthority ? &host_slice : NULL, deadline_ms, NULL); + if (serverAuthority) { + grpc_slice_unref(host_slice); + } + grpc_slice_unref(path_slice); + NSAssert(call != nil, @"Unable to create call."); + if (call == NULL) { + NSLog(@"Unable to create call."); } return call; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 1e3c1d7d97..26600ef3a9 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -39,12 +39,16 @@ NS_ASSUME_NONNULL_BEGIN */ @interface GRPCPooledChannel : NSObject +- (nullable instancetype)init NS_UNAVAILABLE; + ++ (nullable instancetype)new NS_UNAVAILABLE; + /** * Initialize with an actual channel object \a channel and a reference to the channel pool. */ - (nullable instancetype)initWithChannelConfiguration: (GRPCChannelConfiguration *)channelConfiguration - channelPool:(GRPCChannelPool *)channelPool; + channelPool:(GRPCChannelPool *)channelPool NS_DESIGNATED_INITIALIZER; /** * Create a grpc core call object (grpc_call) from this channel. If channel is disconnected, get a @@ -59,17 +63,21 @@ NS_ASSUME_NONNULL_BEGIN * \a unmanagedCallWithPath:completionQueue:callOptions: and decrease channel refcount. If refcount * of the channel becomes 0, return the channel object to channel pool. */ -- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall; +- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall; /** - * Force the channel to disconnect immediately. + * Force the channel to disconnect immediately. Subsequent calls to unmanagedCallWithPath: will + * attempt to reconnect to the remote channel. */ - (void)disconnect; -// The following methods and properties are for test only +@end + +/** Test-only interface for \a GRPCPooledChannel. */ +@interface GRPCPooledChannel (Test) /** - * Return the pointer to the real channel wrapped by the proxy. + * Return the pointer to the raw channel wrapped. */ @property(atomic, readonly) GRPCChannel *wrappedChannel; @@ -81,6 +89,10 @@ NS_ASSUME_NONNULL_BEGIN */ @interface GRPCChannelPool : NSObject +- (nullable instancetype)init NS_UNAVAILABLE; + ++ (nullable instancetype)new NS_UNAVAILABLE; + /** * Get the global channel pool. */ @@ -92,31 +104,20 @@ NS_ASSUME_NONNULL_BEGIN - (GRPCPooledChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; /** - * This method is deprecated. - * - * Destroy all open channels and close their connections. + * Disconnect all channels in this pool. */ -- (void)closeOpenConnections; - -// Test-only methods below +- (void)disconnectAllChannels; -/** - * Get an instance of pool isolated from the global shared pool. This method is for test only. - * Global pool should be used in production. - */ -- (nullable instancetype)init; +@end -/** - * Simulate a network transition event and destroy all channels. This method is for internal and - * test only. - */ -- (void)disconnectAllChannels; +/** Test-only interface for \a GRPCChannelPool. */ +@interface GRPCChannelPool (Test) /** - * Set the destroy delay of channels. A channel should be destroyed if it stayed idle (no active - * call on it) for this period of time. This property is for test only. + * Get an instance of pool isolated from the global shared pool with channels' destroy delay being + * \a destroyDelay. */ -@property(atomic) NSTimeInterval destroyDelay; +- (nullable instancetype)initTestPoolWithDestroyDelay:(NSTimeInterval)destroyDelay; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 7c139b3717..f6615b5840 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -52,10 +52,9 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; __weak GRPCChannelPool *_channelPool; GRPCChannelConfiguration *_channelConfiguration; NSMutableSet *_unmanagedCalls; + GRPCChannel *_wrappedChannel; } -@synthesize wrappedChannel = _wrappedChannel; - - (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration channelPool:(GRPCChannelPool *)channelPool { NSAssert(channelConfiguration != nil, @"channelConfiguration cannot be empty."); @@ -68,11 +67,17 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; _channelPool = channelPool; _channelConfiguration = channelConfiguration; _unmanagedCalls = [NSMutableSet set]; + _wrappedChannel = nil; } return self; } +- (void)dealloc { + NSAssert([_unmanagedCalls count] == 0 && _wrappedChannel == nil, @"Pooled channel should only be" + "destroyed after the wrapped channel is destroyed"); +} + - (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions { @@ -99,31 +104,38 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; return call; } -- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall { - if (unmanagedCall == nil) return; +- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall { + if (unmanagedCall == NULL) { + return; + } grpc_call_unref(unmanagedCall); - BOOL timedDestroy = NO; @synchronized(self) { - if ([_unmanagedCalls containsObject:[NSValue valueWithPointer:unmanagedCall]]) { - [_unmanagedCalls removeObject:[NSValue valueWithPointer:unmanagedCall]]; - if ([_unmanagedCalls count] == 0) { - timedDestroy = YES; - } + NSValue *removedCall = [NSValue valueWithPointer:unmanagedCall]; + [_unmanagedCalls removeObject:removedCall]; + if ([_unmanagedCalls count] == 0) { + _wrappedChannel = nil; + GRPCChannelPool *strongPool = _channelPool; + [strongPool unrefChannelWithConfiguration:_channelConfiguration]; } } - if (timedDestroy) { - [self timedDestroy]; - } } - (void)disconnect { @synchronized(self) { - _wrappedChannel = nil; - [_unmanagedCalls removeAllObjects]; + if (_wrappedChannel != nil) { + _wrappedChannel = nil; + [_unmanagedCalls removeAllObjects]; + GRPCChannelPool *strongPool = _channelPool; + [strongPool unrefChannelWithConfiguration:_channelConfiguration]; + } } } +@end + +@implementation GRPCPooledChannel (Test) + - (GRPCChannel *)wrappedChannel { GRPCChannel *channel = nil; @synchronized(self) { @@ -132,67 +144,52 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; return channel; } -- (void)timedDestroy { - __strong GRPCChannelPool *pool = nil; - @synchronized(self) { - // Check if we still want to destroy the channel. - if ([_unmanagedCalls count] == 0) { - pool = _channelPool; - _wrappedChannel = nil; - } - } - [pool unrefChannelWithConfiguration:_channelConfiguration]; -} - @end /** * A convenience value type for cached channel. */ -@interface GRPCChannelRecord : NSObject +@interface GRPCChannelRecord : NSObject /** Pointer to the raw channel. May be nil when the channel has been destroyed. */ @property GRPCChannel *channel; /** Channel proxy corresponding to this channel configuration. */ -@property GRPCPooledChannel *proxy; +@property GRPCPooledChannel *pooledChannel; /** Last time when a timed destroy is initiated on the channel. */ @property NSDate *timedDestroyDate; /** Reference count of the proxy to the channel. */ -@property NSUInteger refcount; +@property NSUInteger refCount; @end @implementation GRPCChannelRecord -- (id)copyWithZone:(NSZone *)zone { - GRPCChannelRecord *newRecord = [[GRPCChannelRecord allocWithZone:zone] init]; - newRecord.channel = _channel; - newRecord.proxy = _proxy; - newRecord.timedDestroyDate = _timedDestroyDate; - newRecord.refcount = _refcount; +@end - return newRecord; -} +@interface GRPCChannelPool () + +- (instancetype)initInstanceWithDestroyDelay:(NSTimeInterval)destroyDelay NS_DESIGNATED_INITIALIZER; @end @implementation GRPCChannelPool { NSMutableDictionary *_channelPool; dispatch_queue_t _dispatchQueue; + NSTimeInterval _destroyDelay; } + (instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ - gChannelPool = [[GRPCChannelPool alloc] init]; + gChannelPool = [[GRPCChannelPool alloc] initInstanceWithDestroyDelay:kDefaultChannelDestroyDelay]; NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool."); }); return gChannelPool; } -- (instancetype)init { +- (instancetype)initInstanceWithDestroyDelay:(NSTimeInterval)destroyDelay { if ((self = [super init])) { _channelPool = [NSMutableDictionary dictionary]; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 @@ -206,7 +203,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; #endif _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } - _destroyDelay = kDefaultChannelDestroyDelay; + _destroyDelay = destroyDelay; // Connectivity monitor is not required for CFStream char *enableCFStream = getenv(kCFStreamVarName); @@ -217,56 +214,56 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; return self; } +- (void)dealloc { + [GRPCConnectivityMonitor unregisterObserver:self]; +} + - (GRPCPooledChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions { NSAssert(host.length > 0, @"Host must not be empty."); NSAssert(callOptions != nil, @"callOptions must not be empty."); - if (host.length == 0) return nil; - if (callOptions == nil) return nil; + if (host.length == 0 || callOptions == nil) { + return nil; + } - GRPCPooledChannel *channelProxy = nil; + GRPCPooledChannel *pooledChannel = nil; GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; @synchronized(self) { GRPCChannelRecord *record = _channelPool[configuration]; if (record == nil) { record = [[GRPCChannelRecord alloc] init]; - record.proxy = + record.pooledChannel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:configuration channelPool:self]; - record.timedDestroyDate = nil; _channelPool[configuration] = record; - channelProxy = record.proxy; + pooledChannel = record.pooledChannel; } else { - channelProxy = record.proxy; + pooledChannel = record.pooledChannel; } } - return channelProxy; -} - -- (void)closeOpenConnections { - [self disconnectAllChannels]; + return pooledChannel; } - (GRPCChannel *)refChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { GRPCChannel *ret = nil; @synchronized(self) { NSAssert(configuration != nil, @"configuration cannot be empty."); - if (configuration == nil) return nil; + if (configuration == nil) { + return nil; + } GRPCChannelRecord *record = _channelPool[configuration]; NSAssert(record != nil, @"No record corresponding to a proxy."); - if (record == nil) return nil; + if (record == nil) { + return nil; + } + record.refCount++; + record.timedDestroyDate = nil; if (record.channel == nil) { // Channel is already destroyed; record.channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration]; - record.timedDestroyDate = nil; - record.refcount = 1; - ret = record.channel; - } else { - ret = record.channel; - record.timedDestroyDate = nil; - record.refcount++; } + ret = record.channel; } return ret; } @@ -275,11 +272,13 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @synchronized(self) { GRPCChannelRecord *record = _channelPool[configuration]; NSAssert(record != nil, @"No record corresponding to a proxy."); - if (record == nil) return; - NSAssert(record.refcount > 0, @"Inconsistent channel refcount."); - if (record.refcount > 0) { - record.refcount--; - if (record.refcount == 0) { + if (record == nil) { + return; + } + NSAssert(record.refCount > 0, @"Inconsistent channel refcount."); + if (record.refCount > 0) { + record.refCount--; + if (record.refCount == 0) { NSDate *now = [NSDate date]; record.timedDestroyDate = now; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_destroyDelay * NSEC_PER_SEC)), @@ -288,7 +287,6 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; if (now == record.timedDestroyDate) { // Destroy the raw channel and reset related records. record.timedDestroyDate = nil; - record.refcount = 0; record.channel = nil; } } @@ -306,8 +304,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; GRPCChannelRecord *_Nonnull obj, BOOL *_Nonnull stop) { obj.channel = nil; obj.timedDestroyDate = nil; - obj.refcount = 0; - [proxySet addObject:obj.proxy]; + [proxySet addObject:obj.pooledChannel]; }]; } // Disconnect proxies @@ -320,8 +317,12 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; [self disconnectAllChannels]; } -- (void)dealloc { - [GRPCConnectivityMonitor unregisterObserver:self]; +@end + +@implementation GRPCChannelPool (Test) + +- (instancetype)initTestPoolWithDestroyDelay:(NSTimeInterval)destroyDelay { + return [self initInstanceWithDestroyDelay:destroyDelay]; } @end diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 615dfc8556..5788d0a003 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -317,7 +317,7 @@ } - (void)dealloc { - [_channel unrefUnmanagedCall:_call]; + [_channel destroyUnmanagedCall:_call]; _channel = nil; } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 2de2932072..dff88b8591 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -133,18 +133,18 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)cancel { - GRPCCall2 *call; + GRPCCall2 *copiedCall; @synchronized(self) { - call = _call; + copiedCall = _call; _call = nil; if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(_handler.dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; self->_handler = nil; } - [handler closedWithTrailingMetadata:nil + [copiedHandler closedWithTrailingMetadata:nil error:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeCancelled userInfo:@{ @@ -152,9 +152,11 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing @"Canceled by app" }]]; }); + } else { + _handler = nil; } } - [call cancel]; + [copiedCall cancel]; } - (void)writeMessage:(GPBMessage *)message { @@ -182,11 +184,11 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing @synchronized(self) { if (initialMetadata != nil && [_handler respondsToSelector:@selector(initialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; } - [handler receivedInitialMetadata:initialMetadata]; + [copiedHandler receivedInitialMetadata:initialMetadata]; }); } } @@ -200,21 +202,21 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing @synchronized(self) { if (parsed && [_handler respondsToSelector:@selector(receivedProtoMessage:)]) { dispatch_async(_dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; } - [handler receivedProtoMessage:parsed]; + [copiedHandler receivedProtoMessage:parsed]; }); } else if (!parsed && [_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; self->_handler = nil; } - [handler closedWithTrailingMetadata:nil + [copiedHandler closedWithTrailingMetadata:nil error:ErrorForBadProto(message, _responseClass, error)]; }); [_call cancel]; @@ -227,12 +229,12 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing @synchronized(self) { if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ - id handler = nil; + id copiedHandler = nil; @synchronized(self) { - handler = self->_handler; + copiedHandler = self->_handler; self->_handler = nil; } - [handler closedWithTrailingMetadata:trailingMetadata error:error]; + [copiedHandler closedWithTrailingMetadata:trailingMetadata error:error]; }); } _call = nil; diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index 4424801c11..9461945560 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -28,6 +28,8 @@ NSString *kDummyHost = @"dummy.host"; NSString *kDummyHost2 = @"dummy.host.2"; NSString *kDummyPath = @"/dummy/path"; +const NSTimeInterval kDestroyDelay = 1.0; + @interface ChannelPoolTest : XCTestCase @end @@ -39,7 +41,7 @@ NSString *kDummyPath = @"/dummy/path"; } - (void)testCreateChannelAndCall { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; @@ -49,12 +51,12 @@ NSString *kDummyPath = @"/dummy/path"; [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssert(call != NULL); XCTAssertNotNil(channel.wrappedChannel); - [channel unrefUnmanagedCall:call]; + [channel destroyUnmanagedCall:call]; XCTAssertNil(channel.wrappedChannel); } - (void)testCacheChannel { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; GRPCCallOptions *options1 = [[GRPCCallOptions alloc] init]; GRPCCallOptions *options2 = [options1 copy]; GRPCMutableCallOptions *options3 = [options1 mutableCopy]; @@ -80,17 +82,14 @@ NSString *kDummyPath = @"/dummy/path"; XCTAssertNotEqual(channel1.wrappedChannel, channel3.wrappedChannel); XCTAssertNotEqual(channel1.wrappedChannel, channel4.wrappedChannel); XCTAssertNotEqual(channel3.wrappedChannel, channel4.wrappedChannel); - [channel1 unrefUnmanagedCall:call1]; - [channel2 unrefUnmanagedCall:call2]; - [channel3 unrefUnmanagedCall:call3]; - [channel4 unrefUnmanagedCall:call4]; + [channel1 destroyUnmanagedCall:call1]; + [channel2 destroyUnmanagedCall:call2]; + [channel3 destroyUnmanagedCall:call3]; + [channel4 destroyUnmanagedCall:call4]; } - (void)testTimedDestroyChannel { - const NSTimeInterval kDestroyDelay = 1.0; - - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; - pool.destroyDelay = kDestroyDelay; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; @@ -99,25 +98,24 @@ NSString *kDummyPath = @"/dummy/path"; [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; GRPCChannel *wrappedChannel = channel.wrappedChannel; - [channel unrefUnmanagedCall:call]; + [channel destroyUnmanagedCall:call]; // Confirm channel is not destroyed at this time call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertEqual(wrappedChannel, channel.wrappedChannel); - [channel unrefUnmanagedCall:call]; + [channel destroyUnmanagedCall:call]; sleep(kDestroyDelay + 1); // Confirm channel is new at this time call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotEqual(wrappedChannel, channel.wrappedChannel); // Confirm the new channel can create call - call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssert(call != NULL); - [channel unrefUnmanagedCall:call]; + [channel destroyUnmanagedCall:call]; } - (void)testPoolDisconnection { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; @@ -141,12 +139,12 @@ NSString *kDummyPath = @"/dummy/path"; [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); XCTAssertNotEqual(channel.wrappedChannel, wrappedChannel); - [channel unrefUnmanagedCall:call]; - [channel unrefUnmanagedCall:call2]; + [channel destroyUnmanagedCall:call]; + [channel destroyUnmanagedCall:call2]; } - (void)testUnrefCallFromStaleChannel { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] init]; + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; GRPCPooledChannel *channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; @@ -163,12 +161,12 @@ NSString *kDummyPath = @"/dummy/path"; // destroy state XCTAssertNotNil(channel.wrappedChannel); GRPCChannel *wrappedChannel = channel.wrappedChannel; - [channel unrefUnmanagedCall:call]; + [channel destroyUnmanagedCall:call]; XCTAssertNotNil(channel.wrappedChannel); XCTAssertEqual(wrappedChannel, channel.wrappedChannel); // Test unref the call of the current channel will cause the channel going into timed destroy // state - [channel unrefUnmanagedCall:call2]; + [channel destroyUnmanagedCall:call2]; XCTAssertNil(channel.wrappedChannel); } diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index c07c8e6983..5547449092 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -35,7 +35,7 @@ completionQueue:(GRPCCompletionQueue *)queue callOptions:(GRPCCallOptions *)callOptions; -- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall; +- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall; @end @@ -66,7 +66,7 @@ return (grpc_call *)(++_grpcCallCounter); } -- (void)unrefUnmanagedCall:(grpc_call *)unmanagedCall { +- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall { if (_unrefExpectation) [_unrefExpectation fulfill]; } diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 834bf6d661..2cfdd1a003 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -554,13 +554,14 @@ static GRPCProtoMethod *kFullDuplexCallMethod; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; NSString *const kDummyAddress = [NSString stringWithFormat:@"8.8.8.8:1"]; - GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress - path:@"/dummyPath" - requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; + [GRPCCall useInsecureConnectionsForHost:kDummyAddress]; [GRPCCall setMinConnectTimeout:timeout * 1000 initialBackoff:backoff * 1000 maxBackoff:0 forHost:kDummyAddress]; + GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress + path:@"/dummyPath" + requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; NSDate *startTime = [NSDate date]; id responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(id value) { XCTAssert(NO, @"Received message. Should not reach here"); -- cgit v1.2.3 From fdf4b8f2f76cf13f9d41c24775b78727de3c994b Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 26 Nov 2018 17:42:56 -0800 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCallOptions.h | 2 +- src/objective-c/GRPCClient/private/GRPCChannel.h | 3 ++- src/objective-c/GRPCClient/private/GRPCChannel.m | 8 ++++---- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 7 ++++--- src/objective-c/GRPCClient/private/GRPCChannelPool.m | 8 +++++--- src/objective-c/ProtoRPC/ProtoRPC.m | 14 +++++++------- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 48bb11aeeb..158a4745d2 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -64,7 +64,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ -- (void)getTokenWithHandler:(void (^ _Nullable)(NSString * _Nullable token))handler; +- (void)getTokenWithHandler:(void (^_Nullable)(NSString *_Nullable token))handler; @end @interface GRPCCallOptions : NSObject diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index 147015bed1..c01aeccf81 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -51,7 +51,8 @@ NS_ASSUME_NONNULL_BEGIN /** Acquire the dictionary of channel args with current configurations. */ @property(copy, readonly) NSDictionary *channelArgs; -- (nullable instancetype)initWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithHost:(NSString *)host + callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 24cf670d1b..9432e7ab39 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -226,7 +226,7 @@ if (_unmanagedChannel == NULL) return NULL; NSString *serverAuthority = - callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; + callOptions.transportType == GRPCTransportTypeCronet ? nil : callOptions.serverAuthority; NSTimeInterval timeout = callOptions.timeout; NSAssert(timeout >= 0, @"Invalid timeout"); if (timeout < 0) return NULL; @@ -236,9 +236,9 @@ } grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); gpr_timespec deadline_ms = - timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) - : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); + timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) + : gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis((int64_t)(timeout * 1000), GPR_TIMESPAN)); call = grpc_channel_create_call(_unmanagedChannel, NULL, GRPC_PROPAGATE_DEFAULTS, queue.unmanagedQueue, path_slice, serverAuthority ? &host_slice : NULL, deadline_ms, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 26600ef3a9..7f8ee19fe5 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -41,14 +41,15 @@ NS_ASSUME_NONNULL_BEGIN - (nullable instancetype)init NS_UNAVAILABLE; -+ (nullable instancetype)new NS_UNAVAILABLE; ++ (nullable instancetype) new NS_UNAVAILABLE; /** * Initialize with an actual channel object \a channel and a reference to the channel pool. */ - (nullable instancetype)initWithChannelConfiguration: (GRPCChannelConfiguration *)channelConfiguration - channelPool:(GRPCChannelPool *)channelPool NS_DESIGNATED_INITIALIZER; + channelPool:(GRPCChannelPool *)channelPool + NS_DESIGNATED_INITIALIZER; /** * Create a grpc core call object (grpc_call) from this channel. If channel is disconnected, get a @@ -91,7 +92,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable instancetype)init NS_UNAVAILABLE; -+ (nullable instancetype)new NS_UNAVAILABLE; ++ (nullable instancetype) new NS_UNAVAILABLE; /** * Get the global channel pool. diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index f6615b5840..646f1e4b86 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -74,8 +74,9 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } - (void)dealloc { - NSAssert([_unmanagedCalls count] == 0 && _wrappedChannel == nil, @"Pooled channel should only be" - "destroyed after the wrapped channel is destroyed"); + NSAssert([_unmanagedCalls count] == 0 && _wrappedChannel == nil, + @"Pooled channel should only be" + "destroyed after the wrapped channel is destroyed"); } - (grpc_call *)unmanagedCallWithPath:(NSString *)path @@ -183,7 +184,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; + (instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ - gChannelPool = [[GRPCChannelPool alloc] initInstanceWithDestroyDelay:kDefaultChannelDestroyDelay]; + gChannelPool = + [[GRPCChannelPool alloc] initInstanceWithDestroyDelay:kDefaultChannelDestroyDelay]; NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool."); }); return gChannelPool; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index dff88b8591..1db04894d5 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -145,12 +145,12 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing self->_handler = nil; } [copiedHandler closedWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; }); } else { _handler = nil; @@ -217,7 +217,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing self->_handler = nil; } [copiedHandler closedWithTrailingMetadata:nil - error:ErrorForBadProto(message, _responseClass, error)]; + error:ErrorForBadProto(message, _responseClass, error)]; }); [_call cancel]; _call = nil; -- cgit v1.2.3 From fd69f74b2091ae66b609ec7592905d9b20dddf88 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 27 Nov 2018 17:48:55 -0800 Subject: use value64 --- src/objective-c/GRPCClient/private/ChannelArgsUtil.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m index 3135fcff02..c1c65c3384 100644 --- a/src/objective-c/GRPCClient/private/ChannelArgsUtil.m +++ b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m @@ -78,7 +78,7 @@ grpc_channel_args *GRPCBuildChannelArgs(NSDictionary *dictionary) { int64_t value64 = [value longLongValue]; if (value64 <= INT_MAX || value64 >= INT_MIN) { arg->type = GRPC_ARG_INTEGER; - arg->value.integer = [value intValue]; + arg->value.integer = (int)value64; j++; } } else if (value != nil) { -- cgit v1.2.3 From a7c41346d8470e7eb5f10234daa08d09a48fa779 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 28 Nov 2018 11:22:33 -0800 Subject: Add one more cancel test --- src/objective-c/tests/InteropTests.m | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index a9f33aab6f..2492718046 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -655,6 +655,37 @@ BOOL isRemoteInteropTest(NSString *host) { [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testCancelAfterFirstRequestWithV2API { + XCTAssertNotNil([[self class] host]); + __weak XCTestExpectation *completionExpectation = + [self expectationWithDescription:@"Call completed."]; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = self.class.transportType; + options.PEMRootCertificates = self.class.PEMRootCertificates; + options.hostNameOverride = [[self class] hostNameOverride]; + + id request = + [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 requestedResponseSize:@31415]; + + __block GRPCStreamingProtoCall *call = [_service + fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + XCTFail(@"Received unexpected response."); + } + closeCallback:^(NSDictionary *trailingMetadata, + NSError *error) { + XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); + [completionExpectation fulfill]; + }] + callOptions:options]; + + [call writeMessage:request]; + [call cancel]; + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testRPCAfterClosingOpenConnections { XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = -- cgit v1.2.3 From 459da578db5ae9bd95f91be2888236c4870a7314 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 30 Nov 2018 13:43:56 -0800 Subject: Refactor channel pool --- src/objective-c/GRPCClient/GRPCCall.m | 15 +- .../GRPCClient/private/GRPCChannelPool.h | 35 +-- .../GRPCClient/private/GRPCChannelPool.m | 276 ++++++++------------- .../GRPCClient/private/GRPCWrappedCall.h | 13 +- .../GRPCClient/private/GRPCWrappedCall.m | 117 +++++---- .../tests/ChannelTests/ChannelPoolTest.m | 146 ++--------- src/objective-c/tests/ChannelTests/ChannelTests.m | 152 ++++++------ .../xcshareddata/xcschemes/ChannelTests.xcscheme | 5 - 8 files changed, 306 insertions(+), 453 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index bf9441c27e..dad8594a26 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -36,6 +36,8 @@ #import "private/NSDictionary+GRPC.h" #import "private/NSError+GRPC.h" #import "private/utilities.h" +#import "private/GRPCChannelPool.h" +#import "private/GRPCCompletionQueue.h" // At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA, // SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE, @@ -819,8 +821,11 @@ const char *kCFStreamVarName = "grpc_cfstream"; _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; - GRPCWrappedCall *wrappedCall = - [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions]; + GRPCPooledChannel *channel = [[GRPCChannelPool sharedInstance] channelWithHost:_host callOptions:_callOptions]; + GRPCWrappedCall *wrappedCall = [channel wrappedCallWithPath:_path + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:_callOptions]; + if (wrappedCall == nil) { [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeUnavailable @@ -837,12 +842,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; [self sendHeaders]; [self invokeCall]; - - // Connectivity monitor is not required for CFStream - char *enableCFStream = getenv(kCFStreamVarName); - if (enableCFStream == nil || enableCFStream[0] != '1') { - [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)]; - } } - (void)startWithWriteable:(id)writeable { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 7f8ee19fe5..338b6e440f 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -32,10 +32,13 @@ NS_ASSUME_NONNULL_BEGIN @class GRPCChannelPool; @class GRPCCompletionQueue; @class GRPCChannelConfiguration; +@class GRPCWrappedCall; /** - * Channel proxy that can be retained and automatically reestablish connection when the channel is - * disconnected. + * A proxied channel object that can be retained and creates GRPCWrappedCall object from. If a + * raw channel is not present (i.e. no tcp connection to the server) when a GRPCWrappedCall object + * is requested, it issues a connection/reconnection. The behavior of this object is to mimic that + * of gRPC core's channel object. */ @interface GRPCPooledChannel : NSObject @@ -47,24 +50,21 @@ NS_ASSUME_NONNULL_BEGIN * Initialize with an actual channel object \a channel and a reference to the channel pool. */ - (nullable instancetype)initWithChannelConfiguration: - (GRPCChannelConfiguration *)channelConfiguration - channelPool:(GRPCChannelPool *)channelPool - NS_DESIGNATED_INITIALIZER; + (GRPCChannelConfiguration *)channelConfiguration; /** - * Create a grpc core call object (grpc_call) from this channel. If channel is disconnected, get a + * Create a GRPCWrappedCall object (grpc_call) from this channel. If channel is disconnected, get a * new channel object from the channel pool. */ -- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path - completionQueue:(GRPCCompletionQueue *)queue - callOptions:(GRPCCallOptions *)callOptions; +- (nullable GRPCWrappedCall *)wrappedCallWithPath:(NSString *)path + completionQueue:(GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions; /** - * Return ownership and destroy the grpc_call object created by - * \a unmanagedCallWithPath:completionQueue:callOptions: and decrease channel refcount. If refcount - * of the channel becomes 0, return the channel object to channel pool. + * Notify the pooled channel that a wrapped call object is no longer referenced and will be + * dealloc'ed. */ -- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall; +- (void)notifyWrappedCallDealloc:(GRPCWrappedCall *)wrappedCall; /** * Force the channel to disconnect immediately. Subsequent calls to unmanagedCallWithPath: will @@ -77,6 +77,13 @@ NS_ASSUME_NONNULL_BEGIN /** Test-only interface for \a GRPCPooledChannel. */ @interface GRPCPooledChannel (Test) +/** + * Initialize a pooled channel with non-default destroy delay for testing purpose. + */ +- (nullable instancetype)initWithChannelConfiguration: +(GRPCChannelConfiguration *)channelConfiguration + destroyDelay:(NSTimeInterval)destroyDelay; + /** * Return the pointer to the raw channel wrapped. */ @@ -118,7 +125,7 @@ NS_ASSUME_NONNULL_BEGIN * Get an instance of pool isolated from the global shared pool with channels' destroy delay being * \a destroyDelay. */ -- (nullable instancetype)initTestPoolWithDestroyDelay:(NSTimeInterval)destroyDelay; +- (nullable instancetype)initTestPool; @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 646f1e4b86..488766c0ed 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -28,6 +28,8 @@ #import "GRPCSecureChannelFactory.h" #import "utilities.h" #import "version.h" +#import "GRPCWrappedCall.h" +#import "GRPCCompletionQueue.h" #import #include @@ -40,103 +42,139 @@ static dispatch_once_t gInitChannelPool; /** When all calls of a channel are destroyed, destroy the channel after this much seconds. */ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; -@interface GRPCChannelPool () - -- (GRPCChannel *)refChannelWithConfiguration:(GRPCChannelConfiguration *)configuration; - -- (void)unrefChannelWithConfiguration:(GRPCChannelConfiguration *)configuration; - -@end - @implementation GRPCPooledChannel { - __weak GRPCChannelPool *_channelPool; GRPCChannelConfiguration *_channelConfiguration; - NSMutableSet *_unmanagedCalls; + NSTimeInterval _destroyDelay; + + NSHashTable *_wrappedCalls; GRPCChannel *_wrappedChannel; + NSDate *_lastTimedDestroy; + dispatch_queue_t _timerQueue; } -- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration - channelPool:(GRPCChannelPool *)channelPool { - NSAssert(channelConfiguration != nil, @"channelConfiguration cannot be empty."); - NSAssert(channelPool != nil, @"channelPool cannot be empty."); - if (channelPool == nil || channelConfiguration == nil) { - return nil; - } - - if ((self = [super init])) { - _channelPool = channelPool; - _channelConfiguration = channelConfiguration; - _unmanagedCalls = [NSMutableSet set]; - _wrappedChannel = nil; - } - - return self; +- (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { + return [self initWithChannelConfiguration:channelConfiguration destroyDelay:kDefaultChannelDestroyDelay]; } - (void)dealloc { - NSAssert([_unmanagedCalls count] == 0 && _wrappedChannel == nil, - @"Pooled channel should only be" - "destroyed after the wrapped channel is destroyed"); + if ([_wrappedCalls objectEnumerator].allObjects.count != 0) { + NSEnumerator *enumerator = [_wrappedCalls objectEnumerator]; + GRPCWrappedCall *wrappedCall; + while ((wrappedCall = [enumerator nextObject])) { + [wrappedCall channelDisconnected]; + }; + } } -- (grpc_call *)unmanagedCallWithPath:(NSString *)path - completionQueue:(GRPCCompletionQueue *)queue - callOptions:(GRPCCallOptions *)callOptions { +- (GRPCWrappedCall *)wrappedCallWithPath:(NSString *)path +completionQueue:(GRPCCompletionQueue *)queue +callOptions:(GRPCCallOptions *)callOptions { NSAssert(path.length > 0, @"path must not be empty."); NSAssert(queue != nil, @"completionQueue must not be empty."); NSAssert(callOptions, @"callOptions must not be empty."); if (path.length == 0 || queue == nil || callOptions == nil) return NULL; - grpc_call *call = NULL; + GRPCWrappedCall *call = nil; + @synchronized(self) { if (_wrappedChannel == nil) { - __strong GRPCChannelPool *strongPool = _channelPool; - if (strongPool) { - _wrappedChannel = [strongPool refChannelWithConfiguration:_channelConfiguration]; + _wrappedChannel = [[GRPCChannel alloc] initWithChannelConfiguration:_channelConfiguration]; + if (_wrappedChannel == nil) { + NSAssert(_wrappedChannel != nil, @"Unable to get a raw channel for proxy."); + return nil; } - NSAssert(_wrappedChannel != nil, @"Unable to get a raw channel for proxy."); } - call = - [_wrappedChannel unmanagedCallWithPath:path completionQueue:queue callOptions:callOptions]; - if (call != NULL) { - [_unmanagedCalls addObject:[NSValue valueWithPointer:call]]; + _lastTimedDestroy = nil; + + grpc_call *unmanagedCall = [_wrappedChannel unmanagedCallWithPath:path + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:callOptions]; + if (unmanagedCall == NULL) { + NSAssert(unmanagedCall != NULL, @"Unable to create grpc_call object"); + return nil; + } + + call = [[GRPCWrappedCall alloc] initWithUnmanagedCall:unmanagedCall pooledChannel:self]; + if (call == nil) { + NSAssert(call != nil, @"Unable to create GRPCWrappedCall object"); + return nil; } + + [_wrappedCalls addObject:call]; } return call; } -- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall { - if (unmanagedCall == NULL) { +- (void)notifyWrappedCallDealloc:(GRPCWrappedCall *)wrappedCall { + NSAssert(wrappedCall != nil, @"wrappedCall cannot be empty."); + if (wrappedCall == nil) { return; } - - grpc_call_unref(unmanagedCall); @synchronized(self) { - NSValue *removedCall = [NSValue valueWithPointer:unmanagedCall]; - [_unmanagedCalls removeObject:removedCall]; - if ([_unmanagedCalls count] == 0) { - _wrappedChannel = nil; - GRPCChannelPool *strongPool = _channelPool; - [strongPool unrefChannelWithConfiguration:_channelConfiguration]; + if ([_wrappedCalls objectEnumerator].allObjects.count == 0) { + NSDate *now = [NSDate date]; + _lastTimedDestroy = now; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)_destroyDelay * NSEC_PER_SEC), + _timerQueue, ^{ + @synchronized(self) { + if (self->_lastTimedDestroy == now) { + self->_wrappedChannel = nil; + self->_lastTimedDestroy = nil; + } + } + }); } } } - (void)disconnect { + NSHashTable *copiedWrappedCalls = nil; @synchronized(self) { if (_wrappedChannel != nil) { _wrappedChannel = nil; - [_unmanagedCalls removeAllObjects]; - GRPCChannelPool *strongPool = _channelPool; - [strongPool unrefChannelWithConfiguration:_channelConfiguration]; + copiedWrappedCalls = [_wrappedCalls copy]; + [_wrappedCalls removeAllObjects]; } } + NSEnumerator *enumerator = [copiedWrappedCalls objectEnumerator]; + GRPCWrappedCall *wrappedCall; + while ((wrappedCall = [enumerator nextObject])) { + [wrappedCall channelDisconnected]; + } } @end @implementation GRPCPooledChannel (Test) +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration + destroyDelay:(NSTimeInterval)destroyDelay { + NSAssert(channelConfiguration != nil, @"channelConfiguration cannot be empty."); + if (channelConfiguration == nil) { + return nil; + } + + if ((self = [super init])) { + _channelConfiguration = channelConfiguration; + _destroyDelay = destroyDelay; + _wrappedCalls = [[NSHashTable alloc] initWithOptions:NSHashTableWeakMemory capacity:1]; + _wrappedChannel = nil; + _lastTimedDestroy = nil; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + if (@available(iOS 8.0, macOS 10.10, *)) { + _timerQueue = dispatch_queue_create(NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); + } else { +#else + { +#endif + _timerQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } + } + + return self; +} + - (GRPCChannel *)wrappedChannel { GRPCChannel *channel = nil; @synchronized(self) { @@ -147,65 +185,28 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @end -/** - * A convenience value type for cached channel. - */ -@interface GRPCChannelRecord : NSObject - -/** Pointer to the raw channel. May be nil when the channel has been destroyed. */ -@property GRPCChannel *channel; - -/** Channel proxy corresponding to this channel configuration. */ -@property GRPCPooledChannel *pooledChannel; - -/** Last time when a timed destroy is initiated on the channel. */ -@property NSDate *timedDestroyDate; - -/** Reference count of the proxy to the channel. */ -@property NSUInteger refCount; - -@end - -@implementation GRPCChannelRecord - -@end - @interface GRPCChannelPool () -- (instancetype)initInstanceWithDestroyDelay:(NSTimeInterval)destroyDelay NS_DESIGNATED_INITIALIZER; +- (instancetype)initInstance NS_DESIGNATED_INITIALIZER; @end @implementation GRPCChannelPool { - NSMutableDictionary *_channelPool; - dispatch_queue_t _dispatchQueue; - NSTimeInterval _destroyDelay; + NSMutableDictionary *_channelPool; } + (instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ gChannelPool = - [[GRPCChannelPool alloc] initInstanceWithDestroyDelay:kDefaultChannelDestroyDelay]; + [[GRPCChannelPool alloc] initInstance]; NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool."); }); return gChannelPool; } -- (instancetype)initInstanceWithDestroyDelay:(NSTimeInterval)destroyDelay { +- (instancetype)initInstance { if ((self = [super init])) { _channelPool = [NSMutableDictionary dictionary]; -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - if (@available(iOS 8.0, macOS 10.10, *)) { - _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); - } else { -#else - { -#endif - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } - _destroyDelay = destroyDelay; // Connectivity monitor is not required for CFStream char *enableCFStream = getenv(kCFStreamVarName); @@ -231,86 +232,23 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; GRPCChannelConfiguration *configuration = [[GRPCChannelConfiguration alloc] initWithHost:host callOptions:callOptions]; @synchronized(self) { - GRPCChannelRecord *record = _channelPool[configuration]; - if (record == nil) { - record = [[GRPCChannelRecord alloc] init]; - record.pooledChannel = - [[GRPCPooledChannel alloc] initWithChannelConfiguration:configuration channelPool:self]; - _channelPool[configuration] = record; - pooledChannel = record.pooledChannel; - } else { - pooledChannel = record.pooledChannel; + pooledChannel = _channelPool[configuration]; + if (pooledChannel == nil) { + pooledChannel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:configuration]; + _channelPool[configuration] = pooledChannel; } } return pooledChannel; } -- (GRPCChannel *)refChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { - GRPCChannel *ret = nil; - @synchronized(self) { - NSAssert(configuration != nil, @"configuration cannot be empty."); - if (configuration == nil) { - return nil; - } - - GRPCChannelRecord *record = _channelPool[configuration]; - NSAssert(record != nil, @"No record corresponding to a proxy."); - if (record == nil) { - return nil; - } - - record.refCount++; - record.timedDestroyDate = nil; - if (record.channel == nil) { - // Channel is already destroyed; - record.channel = [[GRPCChannel alloc] initWithChannelConfiguration:configuration]; - } - ret = record.channel; - } - return ret; -} - -- (void)unrefChannelWithConfiguration:(GRPCChannelConfiguration *)configuration { - @synchronized(self) { - GRPCChannelRecord *record = _channelPool[configuration]; - NSAssert(record != nil, @"No record corresponding to a proxy."); - if (record == nil) { - return; - } - NSAssert(record.refCount > 0, @"Inconsistent channel refcount."); - if (record.refCount > 0) { - record.refCount--; - if (record.refCount == 0) { - NSDate *now = [NSDate date]; - record.timedDestroyDate = now; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_destroyDelay * NSEC_PER_SEC)), - _dispatchQueue, ^{ - @synchronized(self) { - if (now == record.timedDestroyDate) { - // Destroy the raw channel and reset related records. - record.timedDestroyDate = nil; - record.channel = nil; - } - } - }); - } - } - } -} - - (void)disconnectAllChannels { - NSMutableSet *proxySet = [NSMutableSet set]; + NSDictionary *copiedPooledChannels; @synchronized(self) { - [_channelPool - enumerateKeysAndObjectsUsingBlock:^(GRPCChannelConfiguration *_Nonnull key, - GRPCChannelRecord *_Nonnull obj, BOOL *_Nonnull stop) { - obj.channel = nil; - obj.timedDestroyDate = nil; - [proxySet addObject:obj.pooledChannel]; - }]; + copiedPooledChannels = [NSDictionary dictionaryWithDictionary:_channelPool]; } - // Disconnect proxies - [proxySet enumerateObjectsUsingBlock:^(GRPCPooledChannel *_Nonnull obj, BOOL *_Nonnull stop) { + + // Disconnect pooled channels. + [copiedPooledChannels enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { [obj disconnect]; }]; } @@ -323,8 +261,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; @implementation GRPCChannelPool (Test) -- (instancetype)initTestPoolWithDestroyDelay:(NSTimeInterval)destroyDelay { - return [self initInstanceWithDestroyDelay:destroyDelay]; +- (instancetype)initTestPool { + return [self initInstance]; } @end diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h index 19aa5367c7..0432190528 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h @@ -71,11 +71,16 @@ #pragma mark GRPCWrappedCall +@class GRPCPooledChannel; + @interface GRPCWrappedCall : NSObject -- (instancetype)initWithHost:(NSString *)host - path:(NSString *)path - callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; + ++ (instancetype)new NS_UNAVAILABLE; + +- (instancetype)initWithUnmanagedCall:(grpc_call *)unmanagedCall + pooledChannel:(GRPCPooledChannel *)pooledChannel NS_DESIGNATED_INITIALIZER; - (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void (^)(void))errorHandler; @@ -83,4 +88,6 @@ - (void)cancel; +- (void)channelDisconnected; + @end diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 5788d0a003..7e2d9d3c6d 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -237,37 +237,21 @@ #pragma mark GRPCWrappedCall @implementation GRPCWrappedCall { - GRPCCompletionQueue *_queue; - GRPCPooledChannel *_channel; + __weak GRPCPooledChannel *_channel; grpc_call *_call; } -- (instancetype)init { - return [self initWithHost:nil path:nil callOptions:[[GRPCCallOptions alloc] init]]; -} - -- (instancetype)initWithHost:(NSString *)host - path:(NSString *)path - callOptions:(GRPCCallOptions *)callOptions { - NSAssert(host.length != 0 && path.length != 0, @"path and host cannot be nil."); +- (instancetype)initWithUnmanagedCall:(grpc_call *)unmanagedCall + pooledChannel:(GRPCPooledChannel *)pooledChannel { + NSAssert(unmanagedCall != NULL, @"unmanagedCall cannot be empty."); + NSAssert(pooledChannel != nil, @"pooledChannel cannot be empty."); + if (unmanagedCall == NULL || pooledChannel == nil) { + return nil; + } if ((self = [super init])) { - // Each completion queue consumes one thread. There's a trade to be made between creating and - // consuming too many threads and having contention of multiple calls in a single completion - // queue. Currently we use a singleton queue. - _queue = [GRPCCompletionQueue completionQueue]; - _channel = [[GRPCChannelPool sharedInstance] channelWithHost:host callOptions:callOptions]; - if (_channel == nil) { - NSAssert(_channel != nil, @"Failed to get a channel for the host."); - NSLog(@"Failed to get a channel for the host."); - return nil; - } - _call = [_channel unmanagedCallWithPath:path completionQueue:_queue callOptions:callOptions]; - if (_call == nil) { - NSAssert(_channel != nil, @"Failed to get a channel for the host."); - NSLog(@"Failed to create a call."); - return nil; - } + _call = unmanagedCall; + _channel = pooledChannel; } return self; } @@ -283,42 +267,67 @@ [GRPCOpBatchLog addOpBatchToLog:operations]; #endif - size_t nops = operations.count; - grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op)); - size_t i = 0; - for (GRPCOperation *operation in operations) { - ops_array[i++] = operation.op; - } - grpc_call_error error = - grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(bool success) { - if (!success) { - if (errorHandler) { - errorHandler(); - } else { - return; - } - } - for (GRPCOperation *operation in operations) { - [operation finish]; - } - }), - NULL); - gpr_free(ops_array); - - if (error != GRPC_CALL_OK) { - [NSException + @synchronized (self) { + if (_call != NULL) { + size_t nops = operations.count; + grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op)); + size_t i = 0; + for (GRPCOperation *operation in operations) { + ops_array[i++] = operation.op; + } + grpc_call_error error; + error = grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(bool success) { + if (!success) { + if (errorHandler) { + errorHandler(); + } else { + return; + } + } + for (GRPCOperation *operation in operations) { + [operation finish]; + } + }), + NULL); + gpr_free(ops_array); + + if (error != GRPC_CALL_OK) { + [NSException raise:NSInternalInconsistencyException - format:@"A precondition for calling grpc_call_start_batch wasn't met. Error %i", error]; + format:@"A precondition for calling grpc_call_start_batch wasn't met. Error %i", error]; + } + } } } - (void)cancel { - grpc_call_cancel(_call, NULL); + @synchronized (self) { + if (_call != NULL) { + grpc_call_cancel(_call, NULL); + } + } +} + +- (void)channelDisconnected { + @synchronized (self) { + if (_call != NULL) { + grpc_call_unref(_call); + _call = NULL; + } + } } - (void)dealloc { - [_channel destroyUnmanagedCall:_call]; - _channel = nil; + @synchronized (self) { + if (_call != NULL) { + grpc_call_unref(_call); + _call = NULL; + } + } + __strong GRPCPooledChannel *channel = _channel; + if (channel != nil) { + [channel notifyWrappedCallDealloc:self]; + } } @end diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index 9461945560..dc42d7c341 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -24,11 +24,9 @@ #define TEST_TIMEOUT 32 -NSString *kDummyHost = @"dummy.host"; -NSString *kDummyHost2 = @"dummy.host.2"; -NSString *kDummyPath = @"/dummy/path"; - -const NSTimeInterval kDestroyDelay = 1.0; +static NSString *kDummyHost = @"dummy.host"; +static NSString *kDummyHost2 = @"dummy.host.2"; +static NSString *kDummyPath = @"/dummy/path"; @interface ChannelPoolTest : XCTestCase @@ -40,134 +38,26 @@ const NSTimeInterval kDestroyDelay = 1.0; grpc_init(); } -- (void)testCreateChannelAndCall { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; - GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; - XCTAssertNil(channel.wrappedChannel); - GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = - [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - XCTAssert(call != NULL); - XCTAssertNotNil(channel.wrappedChannel); - [channel destroyUnmanagedCall:call]; - XCTAssertNil(channel.wrappedChannel); -} - -- (void)testCacheChannel { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; +- (void)testCreateAndCacheChannel { + GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPool]; GRPCCallOptions *options1 = [[GRPCCallOptions alloc] init]; GRPCCallOptions *options2 = [options1 copy]; GRPCMutableCallOptions *options3 = [options1 mutableCopy]; options3.transportType = GRPCTransportTypeInsecure; - GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - GRPCPooledChannel *channel1 = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options1]; - grpc_call *call1 = - [channel1 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options1]; - GRPCPooledChannel *channel2 = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options2]; - grpc_call *call2 = - [channel2 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options2]; - GRPCPooledChannel *channel3 = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options3]; - grpc_call *call3 = - [channel3 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options3]; - GRPCPooledChannel *channel4 = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost2 callOptions:options1]; - grpc_call *call4 = - [channel4 unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options1]; - XCTAssertEqual(channel1.wrappedChannel, channel2.wrappedChannel); - XCTAssertNotEqual(channel1.wrappedChannel, channel3.wrappedChannel); - XCTAssertNotEqual(channel1.wrappedChannel, channel4.wrappedChannel); - XCTAssertNotEqual(channel3.wrappedChannel, channel4.wrappedChannel); - [channel1 destroyUnmanagedCall:call1]; - [channel2 destroyUnmanagedCall:call2]; - [channel3 destroyUnmanagedCall:call3]; - [channel4 destroyUnmanagedCall:call4]; -} - -- (void)testTimedDestroyChannel { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; - GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; - GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = - [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - GRPCChannel *wrappedChannel = channel.wrappedChannel; - - [channel destroyUnmanagedCall:call]; - // Confirm channel is not destroyed at this time - call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - XCTAssertEqual(wrappedChannel, channel.wrappedChannel); - - [channel destroyUnmanagedCall:call]; - sleep(kDestroyDelay + 1); - // Confirm channel is new at this time - call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - XCTAssertNotEqual(wrappedChannel, channel.wrappedChannel); - - // Confirm the new channel can create call - XCTAssert(call != NULL); - [channel destroyUnmanagedCall:call]; -} - -- (void)testPoolDisconnection { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; - GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; - GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = - [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - XCTAssertNotNil(channel.wrappedChannel); - GRPCChannel *wrappedChannel = channel.wrappedChannel; - - // Test a new channel is created by requesting a channel from pool - [pool disconnectAllChannels]; - channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; - call = [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - XCTAssertNotNil(channel.wrappedChannel); - XCTAssertNotEqual(wrappedChannel, channel.wrappedChannel); - wrappedChannel = channel.wrappedChannel; - - // Test a new channel is created by requesting a new call from the previous proxy - [pool disconnectAllChannels]; - grpc_call *call2 = - [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - XCTAssertNotNil(channel.wrappedChannel); - XCTAssertNotEqual(channel.wrappedChannel, wrappedChannel); - [channel destroyUnmanagedCall:call]; - [channel destroyUnmanagedCall:call2]; -} - -- (void)testUnrefCallFromStaleChannel { - GRPCChannelPool *pool = [[GRPCChannelPool alloc] initTestPoolWithDestroyDelay:kDestroyDelay]; - GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCPooledChannel *channel = - (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; - GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - grpc_call *call = - [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - - [pool disconnectAllChannels]; - channel = (GRPCPooledChannel *)[pool channelWithHost:kDummyHost callOptions:options]; - grpc_call *call2 = - [channel unmanagedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; - // Test unref the call of a stale channel will not cause the current channel going into timed - // destroy state - XCTAssertNotNil(channel.wrappedChannel); - GRPCChannel *wrappedChannel = channel.wrappedChannel; - [channel destroyUnmanagedCall:call]; - XCTAssertNotNil(channel.wrappedChannel); - XCTAssertEqual(wrappedChannel, channel.wrappedChannel); - // Test unref the call of the current channel will cause the channel going into timed destroy - // state - [channel destroyUnmanagedCall:call2]; - XCTAssertNil(channel.wrappedChannel); + GRPCPooledChannel *channel1 = [pool channelWithHost:kDummyHost callOptions:options1]; + GRPCPooledChannel *channel2 = [pool channelWithHost:kDummyHost callOptions:options2]; + GRPCPooledChannel *channel3 = [pool channelWithHost:kDummyHost callOptions:options3]; + GRPCPooledChannel *channel4 = [pool channelWithHost:kDummyHost2 callOptions:options1]; + + XCTAssertNotNil(channel1); + XCTAssertNotNil(channel2); + XCTAssertNotNil(channel3); + XCTAssertNotNil(channel4); + XCTAssertEqual(channel1, channel2); + XCTAssertNotEqual(channel1, channel3); + XCTAssertNotEqual(channel1, channel4); + XCTAssertNotEqual(channel3, channel4); } @end diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index 5547449092..ee7f8b6fdd 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -22,91 +22,99 @@ #import "../../GRPCClient/private/GRPCChannel.h" #import "../../GRPCClient/private/GRPCChannelPool.h" #import "../../GRPCClient/private/GRPCCompletionQueue.h" +#import "../../GRPCClient/private/GRPCWrappedCall.h" -/* -#define TEST_TIMEOUT 8 - -@interface GRPCChannelFake : NSObject - -- (instancetype)initWithCreateExpectation:(XCTestExpectation *)createExpectation - unrefExpectation:(XCTestExpectation *)unrefExpectation; +static NSString *kDummyHost = @"dummy.host"; +static NSString *kDummyPath = @"/dummy/path"; -- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path - completionQueue:(GRPCCompletionQueue *)queue - callOptions:(GRPCCallOptions *)callOptions; - -- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall; +@interface ChannelTests : XCTestCase @end -@implementation GRPCChannelFake { - __weak XCTestExpectation *_createExpectation; - __weak XCTestExpectation *_unrefExpectation; - long _grpcCallCounter; -} - -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration -*)channelConfiguration { return nil; -} - -- (instancetype)initWithCreateExpectation:(XCTestExpectation *)createExpectation - unrefExpectation:(XCTestExpectation *)unrefExpectation { - if ((self = [super init])) { - _createExpectation = createExpectation; - _unrefExpectation = unrefExpectation; - _grpcCallCounter = 0; - } - return self; -} +@implementation ChannelTests -- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path - completionQueue:(GRPCCompletionQueue *)queue - callOptions:(GRPCCallOptions *)callOptions { - if (_createExpectation) [_createExpectation fulfill]; - return (grpc_call *)(++_grpcCallCounter); ++ (void)setUp { + grpc_init(); } -- (void)destroyUnmanagedCall:(grpc_call *)unmanagedCall { - if (_unrefExpectation) [_unrefExpectation fulfill]; +- (void)testPooledChannelCreatingChannel { + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCChannelConfiguration *config = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost + callOptions:options]; + GRPCPooledChannel *channel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:config]; + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + GRPCWrappedCall *wrappedCall = [channel wrappedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotNil(channel.wrappedChannel); + (void)wrappedCall; } -@end - -@interface GRPCChannelPoolFake : NSObject - -- (instancetype)initWithDelayedDestroyExpectation:(XCTestExpectation *)delayedDestroyExpectation; - -- (GRPCChannel *)rawChannelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; - -- (void)delayedDestroyChannel; - -@end - -@implementation GRPCChannelPoolFake { - __weak XCTestExpectation *_delayedDestroyExpectation; -} - -- (instancetype)initWithDelayedDestroyExpectation:(XCTestExpectation *)delayedDestroyExpectation { - if ((self = [super init])) { - _delayedDestroyExpectation = delayedDestroyExpectation; +- (void)testTimedDestroyChannel { + const NSTimeInterval kDestroyDelay = 1.0; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCChannelConfiguration *config = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost + callOptions:options]; + GRPCPooledChannel *channel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:config + destroyDelay:kDestroyDelay]; + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + GRPCWrappedCall *wrappedCall; + GRPCChannel *wrappedChannel; + @autoreleasepool { + wrappedCall = [channel wrappedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotNil(channel.wrappedChannel); + + // Unref and ref channel immediately; expect using the same raw channel. + wrappedChannel = channel.wrappedChannel; + + wrappedCall = nil; + wrappedCall = [channel wrappedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertEqual(channel.wrappedChannel, wrappedChannel); + + // Unref and ref channel after destroy delay; expect a new raw channel. + wrappedCall = nil; } - return self; -} - -- (void)delayedDestroyChannel { - if (_delayedDestroyExpectation) [_delayedDestroyExpectation fulfill]; + sleep(kDestroyDelay + 1); + XCTAssertNil(channel.wrappedChannel); + wrappedCall = [channel wrappedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotEqual(channel.wrappedChannel, wrappedChannel); } -@end */ - -@interface ChannelTests : XCTestCase - -@end - -@implementation ChannelTests - -+ (void)setUp { - grpc_init(); +- (void)testDisconnect { + const NSTimeInterval kDestroyDelay = 1.0; + GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; + GRPCChannelConfiguration *config = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost + callOptions:options]; + GRPCPooledChannel *channel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:config + destroyDelay:kDestroyDelay]; + GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; + GRPCWrappedCall *wrappedCall = [channel wrappedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotNil(channel.wrappedChannel); + + // Disconnect; expect wrapped channel to be dropped + [channel disconnect]; + XCTAssertNil(channel.wrappedChannel); + + // Create a new call and unref the old call; confirm that destroy of the old call does not make + // the channel disconnect, even after the destroy delay. + GRPCWrappedCall *wrappedCall2 = [channel wrappedCallWithPath:kDummyPath + completionQueue:cq + callOptions:options]; + XCTAssertNotNil(channel.wrappedChannel); + GRPCChannel *wrappedChannel = channel.wrappedChannel; + wrappedCall = nil; + sleep(kDestroyDelay + 1); + XCTAssertNotNil(channel.wrappedChannel); + XCTAssertEqual(wrappedChannel, channel.wrappedChannel); + (void)wrappedCall2; } @end diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme index 8c8623d7b2..acae965bed 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme @@ -37,11 +37,6 @@ BlueprintName = "ChannelTests" ReferencedContainer = "container:Tests.xcodeproj"> - - - - -- cgit v1.2.3 From dfec57a9a9ebfbe92709498074eb184527ef599e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 5 Dec 2018 22:52:12 -0800 Subject: Channel pool polishments --- .../GRPCClient/private/GRPCChannelPool.h | 5 +-- .../GRPCClient/private/GRPCChannelPool.m | 41 ++++++++++++---------- .../GRPCClient/private/GRPCWrappedCall.m | 10 +++--- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 338b6e440f..7c6f2b3bbf 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -67,8 +67,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)notifyWrappedCallDealloc:(GRPCWrappedCall *)wrappedCall; /** - * Force the channel to disconnect immediately. Subsequent calls to unmanagedCallWithPath: will - * attempt to reconnect to the remote channel. + * Force the channel to disconnect immediately. GRPCWrappedCall objects previously created with + * \a wrappedCallWithPath are failed if not already finished. Subsequent calls to + * unmanagedCallWithPath: will attempt to reconnect to the remote channel. */ - (void)disconnect; diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 488766c0ed..391022efd1 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -57,7 +57,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } - (void)dealloc { - if ([_wrappedCalls objectEnumerator].allObjects.count != 0) { + // Disconnect GRPCWrappedCall objects created but not yet removed + if (_wrappedCalls.allObjects.count != 0) { NSEnumerator *enumerator = [_wrappedCalls objectEnumerator]; GRPCWrappedCall *wrappedCall; while ((wrappedCall = [enumerator nextObject])) { @@ -111,13 +112,17 @@ callOptions:(GRPCCallOptions *)callOptions { return; } @synchronized(self) { - if ([_wrappedCalls objectEnumerator].allObjects.count == 0) { + // Detect if all objects weakly referenced in _wrappedCalls are (implicitly) removed. In such + // case the channel is no longer referenced by a grpc_call object and can be destroyed after + // a certain delay. + if (_wrappedCalls.allObjects.count == 0) { NSDate *now = [NSDate date]; + NSAssert(now != nil, @"Unable to create NSDate object 'now'."); _lastTimedDestroy = now; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)_destroyDelay * NSEC_PER_SEC), _timerQueue, ^{ @synchronized(self) { - if (self->_lastTimedDestroy == now) { + if (now != nil && self->_lastTimedDestroy == now) { self->_wrappedChannel = nil; self->_lastTimedDestroy = nil; } @@ -128,17 +133,15 @@ callOptions:(GRPCCallOptions *)callOptions { } - (void)disconnect { - NSHashTable *copiedWrappedCalls = nil; + NSArray *copiedWrappedCalls = nil; @synchronized(self) { if (_wrappedChannel != nil) { _wrappedChannel = nil; - copiedWrappedCalls = [_wrappedCalls copy]; + copiedWrappedCalls = _wrappedCalls.allObjects; [_wrappedCalls removeAllObjects]; } } - NSEnumerator *enumerator = [copiedWrappedCalls objectEnumerator]; - GRPCWrappedCall *wrappedCall; - while ((wrappedCall = [enumerator nextObject])) { + for (GRPCWrappedCall *wrappedCall in copiedWrappedCalls) { [wrappedCall channelDisconnected]; } } @@ -155,9 +158,9 @@ callOptions:(GRPCCallOptions *)callOptions { } if ((self = [super init])) { - _channelConfiguration = channelConfiguration; + _channelConfiguration = [channelConfiguration copy]; _destroyDelay = destroyDelay; - _wrappedCalls = [[NSHashTable alloc] initWithOptions:NSHashTableWeakMemory capacity:1]; + _wrappedCalls = [NSHashTable weakObjectsHashTable]; _wrappedChannel = nil; _lastTimedDestroy = nil; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 @@ -187,7 +190,7 @@ callOptions:(GRPCCallOptions *)callOptions { @interface GRPCChannelPool () -- (instancetype)initInstance NS_DESIGNATED_INITIALIZER; +- (instancetype)initPrivate NS_DESIGNATED_INITIALIZER; @end @@ -198,13 +201,13 @@ callOptions:(GRPCCallOptions *)callOptions { + (instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ gChannelPool = - [[GRPCChannelPool alloc] initInstance]; + [[GRPCChannelPool alloc] initPrivate]; NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool."); }); return gChannelPool; } -- (instancetype)initInstance { +- (instancetype)initPrivate { if ((self = [super init])) { _channelPool = [NSMutableDictionary dictionary]; @@ -242,15 +245,15 @@ callOptions:(GRPCCallOptions *)callOptions { } - (void)disconnectAllChannels { - NSDictionary *copiedPooledChannels; + NSArray *copiedPooledChannels; @synchronized(self) { - copiedPooledChannels = [NSDictionary dictionaryWithDictionary:_channelPool]; + copiedPooledChannels = _channelPool.allValues; } // Disconnect pooled channels. - [copiedPooledChannels enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - [obj disconnect]; - }]; + for (GRPCPooledChannel *pooledChannel in copiedPooledChannels) { + [pooledChannel disconnect]; + } } - (void)connectivityChange:(NSNotification *)note { @@ -262,7 +265,7 @@ callOptions:(GRPCCallOptions *)callOptions { @implementation GRPCChannelPool (Test) - (instancetype)initTestPool { - return [self initInstance]; + return [self initPrivate]; } @end diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 7e2d9d3c6d..727c9e0a88 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -237,7 +237,7 @@ #pragma mark GRPCWrappedCall @implementation GRPCWrappedCall { - __weak GRPCPooledChannel *_channel; + GRPCPooledChannel *_pooledChannel; grpc_call *_call; } @@ -251,7 +251,7 @@ if ((self = [super init])) { _call = unmanagedCall; - _channel = pooledChannel; + _pooledChannel = pooledChannel; } return self; } @@ -324,10 +324,8 @@ _call = NULL; } } - __strong GRPCPooledChannel *channel = _channel; - if (channel != nil) { - [channel notifyWrappedCallDealloc:self]; - } + __strong GRPCPooledChannel *channel = _pooledChannel; + [channel notifyWrappedCallDealloc:self]; } @end -- cgit v1.2.3 From 70f34521deaeaf0d783f30d121fd26787135ac04 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 6 Dec 2018 12:08:43 -0800 Subject: isolate start: function from proto calls --- src/objective-c/ProtoRPC/ProtoRPC.h | 10 +++++++ src/objective-c/ProtoRPC/ProtoRPC.m | 19 +++++++++---- src/objective-c/tests/InteropTests.m | 53 ++++++++++++++++++++++++++++++++---- 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 2623aecb82..949f52d1b5 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -76,6 +76,11 @@ NS_ASSUME_NONNULL_BEGIN callOptions:(nullable GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; +/** + * Start the call. This function must only be called once for each instance. + */ +- (void)start; + /** * Cancel the request of this call at best effort. It attempts to notify the server that the RPC * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code @@ -101,6 +106,11 @@ NS_ASSUME_NONNULL_BEGIN callOptions:(nullable GRPCCallOptions *)callOptions responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; +/** + * Start the call. This function must only be called once for each instance. + */ +- (void)start; + /** * Cancel the request of this call at best effort. It attempts to notify the server that the RPC * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 1db04894d5..09f8d03af6 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -47,6 +47,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing @implementation GRPCUnaryProtoCall { GRPCStreamingProtoCall *_call; + GPBMessage *_message; } - (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions @@ -54,17 +55,24 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { + NSAssert(message != nil, @"message cannot be empty."); + NSAssert(responseClass != nil, @"responseClass cannot be empty."); if ((self = [super init])) { _call = [[GRPCStreamingProtoCall alloc] initWithRequestOptions:requestOptions responseHandler:handler callOptions:callOptions responseClass:responseClass]; - [_call writeMessage:message]; - [_call finish]; + _message = [message copy]; } return self; } +- (void)start { + [_call start]; + [_call writeMessage:_message]; + [_call finish]; +} + - (void)cancel { [_call cancel]; _call = nil; @@ -120,15 +128,14 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } dispatch_set_target_queue(_dispatchQueue, handler.dispatchQueue); - [self start]; + _call = [[GRPCCall2 alloc] initWithRequestOptions:_requestOptions + responseHandler:self + callOptions:_callOptions]; } return self; } - (void)start { - _call = [[GRPCCall2 alloc] initWithRequestOptions:_requestOptions - responseHandler:self - callOptions:_callOptions]; [_call start]; } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 2492718046..e94fd1493a 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -197,7 +197,7 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testEmptyUnaryRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"]; + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnaryWithV2API"]; GPBEmpty *request = [GPBEmpty message]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; @@ -205,7 +205,7 @@ BOOL isRemoteInteropTest(NSString *host) { options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; - [_service + GRPCUnaryProtoCall *call = [_service emptyCallWithMessage:request responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id message) { @@ -219,6 +219,7 @@ BOOL isRemoteInteropTest(NSString *host) { XCTAssertNil(error, @"Unexpected error: %@", error); }] callOptions:options]; + [call start]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -246,6 +247,44 @@ BOOL isRemoteInteropTest(NSString *host) { [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testLargeUnaryRPCWithV2API { + XCTAssertNotNil([[self class] host]); + __weak XCTestExpectation *expectRecvMessage = [self expectationWithDescription:@"LargeUnaryWithV2API received message"]; + __weak XCTestExpectation *expectRecvComplete = [self expectationWithDescription:@"LargeUnaryWithV2API received complete"]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.responseType = RMTPayloadType_Compressable; + request.responseSize = 314159; + request.payload.body = [NSMutableData dataWithLength:271828]; + + GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; + options.transportType = [[self class] transportType]; + options.PEMRootCertificates = [[self class] PEMRootCertificates]; + options.hostNameOverride = [[self class] hostNameOverride]; + + GRPCUnaryProtoCall *call = [_service + unaryCallWithMessage:request + responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + XCTAssertNotNil(message); + if (message) { + RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; + expectedResponse.payload.type = RMTPayloadType_Compressable; + expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; + XCTAssertEqualObjects(message, expectedResponse); + + [expectRecvMessage fulfill]; + } + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNil(error, @"Unexpected error: %@", error); + [expectRecvComplete fulfill]; + }] + callOptions:options]; + [call start]; + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + - (void)testPacketCoalescing { XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"]; @@ -473,7 +512,7 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testPingPongRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"]; + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPongWithV2API"]; NSArray *requests = @[ @27182, @8, @1828, @45904 ]; NSArray *responses = @[ @31415, @9, @2653, @58979 ]; @@ -517,6 +556,7 @@ BOOL isRemoteInteropTest(NSString *host) { [expectation fulfill]; }] callOptions:options]; + [call start]; [call writeMessage:request]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; @@ -562,7 +602,7 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testCancelAfterBeginRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBegin"]; + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBeginWithV2API"]; // A buffered pipe to which we never write any value acts as a writer that just hangs. __block GRPCStreamingProtoCall *call = [_service @@ -577,6 +617,7 @@ BOOL isRemoteInteropTest(NSString *host) { [expectation fulfill]; }] callOptions:nil]; + [call start]; [call cancel]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; @@ -650,7 +691,7 @@ BOOL isRemoteInteropTest(NSString *host) { [completionExpectation fulfill]; }] callOptions:options]; - + [call start]; [call writeMessage:request]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -680,7 +721,7 @@ BOOL isRemoteInteropTest(NSString *host) { [completionExpectation fulfill]; }] callOptions:options]; - + [call start]; [call writeMessage:request]; [call cancel]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; -- cgit v1.2.3 From 76f1ec16e1880605215beb60a204b0cab7c36b2d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 6 Dec 2018 12:42:27 -0800 Subject: sensible nullability annotation for old API --- src/objective-c/GRPCClient/GRPCCall.h | 22 ++++++++++++---------- src/objective-c/GRPCClient/GRPCCall.m | 7 +++---- src/objective-c/ProtoRPC/ProtoRPC.h | 10 +++++----- .../examples/SwiftSample/ViewController.swift | 10 +++++----- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 214969af23..51a82263bf 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -282,6 +282,8 @@ NS_ASSUME_NONNULL_END */ @interface GRPCCall : GRXWriter +- (instancetype)init NS_UNAVAILABLE; + /** * The container of the request headers of an RPC conforms to this protocol, which is a subset of * NSMutableDictionary's interface. It will become a NSMutableDictionary later on. @@ -306,7 +308,7 @@ NS_ASSUME_NONNULL_END * * The property is initialized to an empty NSMutableDictionary. */ -@property(nullable, atomic, readonly) NSMutableDictionary *requestHeaders; +@property(nonnull, atomic, readonly) NSMutableDictionary *requestHeaders; /** * This dictionary is populated with the HTTP headers received from the server. This happens before @@ -339,9 +341,9 @@ NS_ASSUME_NONNULL_END * host parameter should not contain the scheme (http:// or https://), only the name or IP addr * and the port number, for example @"localhost:5050". */ -- (nullable instancetype)initWithHost:(nullable NSString *)host - path:(nullable NSString *)path - requestsWriter:(nullable GRXWriter *)requestWriter; +- (nullable instancetype)initWithHost:(nonnull NSString *)host + path:(nonnull NSString *)path + requestsWriter:(nonnull GRXWriter *)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and @@ -353,11 +355,11 @@ NS_ASSUME_NONNULL_END * The following methods are deprecated. */ + (void)setCallSafety:(GRPCCallSafety)callSafety - host:(nullable NSString *)host - path:(nullable NSString *)path; + host:(nonnull NSString *)host + path:(nonnull NSString *)path; @property(nullable, atomic, copy, readwrite) NSString *serverName; @property NSTimeInterval timeout; -- (void)setResponseDispatchQueue:(nullable dispatch_queue_t)queue; +- (void)setResponseDispatchQueue:(nonnull dispatch_queue_t)queue; @end @@ -368,11 +370,11 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; -- (nullable id)objectForKeyedSubscript:(nullable id)key; -- (void)setObject:(nullable id)obj forKeyedSubscript:(nullable id)key; +- (nullable id)objectForKeyedSubscript:(nonnull id)key; +- (void)setObject:(nullable id)obj forKeyedSubscript:(nonnull id)key; - (void)removeAllObjects; -- (void)removeObjectForKey:(nullable id)key; +- (void)removeObjectForKey:(nonnull id)key; @end #pragma clang diagnostic push diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index dad8594a26..9b3bcd385e 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -445,6 +445,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; } + (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path { + if (host.length == 0 || path.length == 0) { + return; + } NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path]; switch (callSafety) { case GRPCCallSafetyDefault: @@ -466,10 +469,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; return [callFlags[hostAndPath] intValue]; } -- (instancetype)init { - return [self initWithHost:nil path:nil requestsWriter:nil]; -} - // Designated initializer - (instancetype)initWithHost:(NSString *)host path:(NSString *)path diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 949f52d1b5..1819fa9379 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -142,11 +142,11 @@ __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC * addr and the port number, for example @"localhost:5050". */ - - (nullable instancetype)initWithHost : (nullable NSString *)host method - : (nullable GRPCProtoMethod *)method requestsWriter - : (nullable GRXWriter *)requestsWriter responseClass - : (nullable Class)responseClass responsesWriteable - : (nullable id)responsesWriteable NS_DESIGNATED_INITIALIZER; + (nullable instancetype)initWithHost : (nonnull NSString *)host method + : (nonnull GRPCProtoMethod *)method requestsWriter + : (nonnull GRXWriter *)requestsWriter responseClass + : (nonnull Class)responseClass responsesWriteable + : (nonnull id)responsesWriteable NS_DESIGNATED_INITIALIZER; - (void)start; @end diff --git a/src/objective-c/examples/SwiftSample/ViewController.swift b/src/objective-c/examples/SwiftSample/ViewController.swift index 0ba6e21f02..4ed10266a4 100644 --- a/src/objective-c/examples/SwiftSample/ViewController.swift +++ b/src/objective-c/examples/SwiftSample/ViewController.swift @@ -54,8 +54,8 @@ class ViewController: UIViewController { } else { NSLog("2. Finished with error: \(error!)") } - NSLog("2. Response headers: \(RPC.responseHeaders)") - NSLog("2. Response trailers: \(RPC.responseTrailers)") + NSLog("2. Response headers: \(String(describing: RPC.responseHeaders))") + NSLog("2. Response trailers: \(String(describing: RPC.responseTrailers))") } // TODO(jcanizales): Revert to using subscript syntax once XCode 8 is released. @@ -68,7 +68,7 @@ class ViewController: UIViewController { let method = GRPCProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall")! - let requestsWriter = GRXWriter(value: request.data()) + let requestsWriter = GRXWriter(value: request.data())! let call = GRPCCall(host: RemoteHost, path: method.httpPath, requestsWriter: requestsWriter)! @@ -80,8 +80,8 @@ class ViewController: UIViewController { } else { NSLog("3. Finished with error: \(error!)") } - NSLog("3. Response headers: \(call.responseHeaders)") - NSLog("3. Response trailers: \(call.responseTrailers)") + NSLog("3. Response headers: \(String(describing: call.responseHeaders))") + NSLog("3. Response trailers: \(String(describing: call.responseTrailers))") }) } } -- cgit v1.2.3 From eeced98fc556c6a5bc3a5dedc171c98747217078 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 6 Dec 2018 13:08:34 -0800 Subject: Rename handlers to didXxx --- src/objective-c/GRPCClient/GRPCCall.h | 8 ++++---- src/objective-c/GRPCClient/GRPCCall.m | 16 ++++++++-------- src/objective-c/ProtoRPC/ProtoRPC.h | 12 ++++++------ src/objective-c/ProtoRPC/ProtoRPC.m | 24 ++++++++++++------------ src/objective-c/tests/APIv2Tests/APIv2Tests.m | 6 +++--- src/objective-c/tests/InteropTests.m | 6 +++--- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 51a82263bf..985743433c 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -158,13 +158,13 @@ extern NSString *const kGRPCTrailersKey; /** * Issued when initial metadata is received from the server. */ -- (void)receivedInitialMetadata:(nullable NSDictionary *)initialMetadata; +- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata; /** * Issued when a message is received from the server. The message is the raw data received from the * server, with decompression and without proto deserialization. */ -- (void)receivedRawMessage:(nullable NSData *)message; +- (void)didReceiveRawMessage:(nullable NSData *)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -172,7 +172,7 @@ extern NSString *const kGRPCTrailersKey; * is non-nil and contains the corresponding error information, including gRPC error codes and * error descriptions. */ -- (void)closedWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata +- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata error:(nullable NSError *)error; @required @@ -247,7 +247,7 @@ extern NSString *const kGRPCTrailersKey; /** * Cancel the request of this call at best effort. It attempts to notify the server that the RPC - * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code + * should be cancelled, and issue didCloseWithTrailingMetadata:error: callback with error code * CANCELED if no other error code has already been issued. */ - (void)cancel; diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 9b3bcd385e..48253677bd 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -250,7 +250,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; _call = nil; _pipe = nil; - if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ // Copy to local so that block is freed after cancellation completes. id copiedHandler = nil; @@ -259,7 +259,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; self->_handler = nil; } - [copiedHandler closedWithTrailingMetadata:nil + [copiedHandler didCloseWithTrailingMetadata:nil error:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeCancelled userInfo:@{ @@ -321,13 +321,13 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { @synchronized(self) { if (initialMetadata != nil && - [_handler respondsToSelector:@selector(receivedInitialMetadata:)]) { + [_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { copiedHandler = self->_handler; } - [copiedHandler receivedInitialMetadata:initialMetadata]; + [copiedHandler didReceiveInitialMetadata:initialMetadata]; }); } } @@ -335,13 +335,13 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)issueMessage:(id)message { @synchronized(self) { - if (message != nil && [_handler respondsToSelector:@selector(receivedRawMessage:)]) { + if (message != nil && [_handler respondsToSelector:@selector(didReceiveRawMessage:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { copiedHandler = self->_handler; } - [copiedHandler receivedRawMessage:message]; + [copiedHandler didReceiveRawMessage:message]; }); } } @@ -349,7 +349,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { @synchronized(self) { - if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { @@ -357,7 +357,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; // Clean up _handler so that no more responses are reported to the handler. self->_handler = nil; } - [copiedHandler closedWithTrailingMetadata:trailingMetadata error:error]; + [copiedHandler didCloseWithTrailingMetadata:trailingMetadata error:error]; }); } else { _handler = nil; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 1819fa9379..287aa0369b 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -33,12 +33,12 @@ NS_ASSUME_NONNULL_BEGIN /** * Issued when initial metadata is received from the server. */ -- (void)receivedInitialMetadata:(nullable NSDictionary *)initialMetadata; +- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata; /** * Issued when a message is received from the server. The message is the deserialized proto object. */ -- (void)receivedProtoMessage:(nullable GPBMessage *)message; +- (void)didReceiveProtoMessage:(nullable GPBMessage *)message; /** * Issued when a call finished. If the call finished successfully, \a error is nil and \a @@ -46,8 +46,8 @@ NS_ASSUME_NONNULL_BEGIN * is non-nil and contains the corresponding error information, including gRPC error codes and * error descriptions. */ -- (void)closedWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata - error:(nullable NSError *)error; +- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata + error:(nullable NSError *)error; @required @@ -83,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Cancel the request of this call at best effort. It attempts to notify the server that the RPC - * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code + * should be cancelled, and issue didCloseWithTrailingMetadata:error: callback with error code * CANCELED if no other error code has already been issued. */ - (void)cancel; @@ -113,7 +113,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Cancel the request of this call at best effort. It attempts to notify the server that the RPC - * should be cancelled, and issue closedWithTrailingMetadata:error: callback with error code + * should be cancelled, and issue didCloseWithTrailingMetadata:error: callback with error code * CANCELED if no other error code has already been issued. */ - (void)cancel; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 09f8d03af6..886e31ce58 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -144,14 +144,14 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing @synchronized(self) { copiedCall = _call; _call = nil; - if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { dispatch_async(_handler.dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { copiedHandler = self->_handler; self->_handler = nil; } - [copiedHandler closedWithTrailingMetadata:nil + [copiedHandler didCloseWithTrailingMetadata:nil error:[NSError errorWithDomain:kGRPCErrorDomain code:GRPCErrorCodeCancelled userInfo:@{ @@ -187,7 +187,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing [call finish]; } -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { +- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { @synchronized(self) { if (initialMetadata != nil && [_handler respondsToSelector:@selector(initialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ @@ -195,35 +195,35 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing @synchronized(self) { copiedHandler = self->_handler; } - [copiedHandler receivedInitialMetadata:initialMetadata]; + [copiedHandler didReceiveInitialMetadata:initialMetadata]; }); } } } -- (void)receivedRawMessage:(NSData *)message { +- (void)didReceiveRawMessage:(NSData *)message { if (message == nil) return; NSError *error = nil; GPBMessage *parsed = [_responseClass parseFromData:message error:&error]; @synchronized(self) { - if (parsed && [_handler respondsToSelector:@selector(receivedProtoMessage:)]) { + if (parsed && [_handler respondsToSelector:@selector(didReceiveProtoMessage:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { copiedHandler = self->_handler; } - [copiedHandler receivedProtoMessage:parsed]; + [copiedHandler didReceiveProtoMessage:parsed]; }); } else if (!parsed && - [_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + [_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { copiedHandler = self->_handler; self->_handler = nil; } - [copiedHandler closedWithTrailingMetadata:nil + [copiedHandler didCloseWithTrailingMetadata:nil error:ErrorForBadProto(message, _responseClass, error)]; }); [_call cancel]; @@ -232,16 +232,16 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { +- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { @synchronized(self) { - if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { + if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { copiedHandler = self->_handler; self->_handler = nil; } - [copiedHandler closedWithTrailingMetadata:trailingMetadata error:error]; + [copiedHandler didCloseWithTrailingMetadata:trailingMetadata error:error]; }); } _call = nil; diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index 32f2122f79..ca7bf47283 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -81,19 +81,19 @@ static const NSTimeInterval kTestTimeout = 16; return self; } -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { +- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { if (self->_initialMetadataCallback) { self->_initialMetadataCallback(initialMetadata); } } -- (void)receivedRawMessage:(GPBMessage *)message { +- (void)didReceiveRawMessage:(GPBMessage *)message { if (self->_messageCallback) { self->_messageCallback(message); } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { +- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { if (self->_closeCallback) { self->_closeCallback(trailingMetadata, error); } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index e94fd1493a..d17a07f929 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -102,19 +102,19 @@ BOOL isRemoteInteropTest(NSString *host) { return self; } -- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata { +- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { if (_initialMetadataCallback) { _initialMetadataCallback(initialMetadata); } } -- (void)receivedProtoMessage:(GPBMessage *)message { +- (void)didReceiveProtoMessage:(GPBMessage *)message { if (_messageCallback) { _messageCallback(message); } } -- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { +- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { if (_closeCallback) { _closeCallback(trailingMetadata, error); } -- cgit v1.2.3 From f9e50322bf1d6be736b415831eea44130b9dedfe Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 6 Dec 2018 15:58:53 -0800 Subject: batch fix --- src/objective-c/GRPCClient/GRPCCall.h | 16 +++---- src/objective-c/GRPCClient/GRPCCall.m | 4 +- .../GRPCClient/private/GRPCChannelPool+Test.h | 49 ++++++++++++++++++++++ .../GRPCClient/private/GRPCChannelPool.h | 28 ------------- .../GRPCClient/private/GRPCChannelPool.m | 7 ++-- src/objective-c/ProtoRPC/ProtoRPC.h | 16 +++---- src/objective-c/ProtoRPC/ProtoRPC.m | 5 +-- .../tests/ChannelTests/ChannelPoolTest.m | 2 +- src/objective-c/tests/ChannelTests/ChannelTests.m | 1 + 9 files changed, 73 insertions(+), 55 deletions(-) create mode 100644 src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 985743433c..6d8b9c1b12 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -153,6 +153,14 @@ extern NSString *const kGRPCTrailersKey; /** An object can implement this protocol to receive responses from server from a call. */ @protocol GRPCResponseHandler +@required + +/** + * All the responses must be issued to a user-provided dispatch queue. This property specifies the + * dispatch queue to be used for issuing the notifications. + */ +@property(atomic, readonly) dispatch_queue_t dispatchQueue; + @optional /** @@ -175,14 +183,6 @@ extern NSString *const kGRPCTrailersKey; - (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata error:(nullable NSError *)error; -@required - -/** - * All the responses must be issued to a user-provided dispatch queue. This property specifies the - * dispatch queue to be used for issuing the notifications. - */ -@property(atomic, readonly) dispatch_queue_t dispatchQueue; - @end /** diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 48253677bd..e75ca7193a 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -856,9 +856,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; _retainSelf = self; if (_callOptions == nil) { - GRPCMutableCallOptions *callOptions; - - callOptions = [[GRPCHost callOptionsForHost:_host] mutableCopy]; + GRPCMutableCallOptions *callOptions = [[GRPCHost callOptionsForHost:_host] mutableCopy]; if (_serverName.length != 0) { callOptions.serverAuthority = _serverName; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h b/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h new file mode 100644 index 0000000000..4e7c988585 --- /dev/null +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GRPCChannelPool.h" + +/** Test-only interface for \a GRPCPooledChannel. */ +@interface GRPCPooledChannel (Test) + +/** + * Initialize a pooled channel with non-default destroy delay for testing purpose. + */ +- (nullable instancetype)initWithChannelConfiguration: +(GRPCChannelConfiguration *)channelConfiguration + destroyDelay:(NSTimeInterval)destroyDelay; + +/** + * Return the pointer to the raw channel wrapped. + */ +@property(atomic, readonly) GRPCChannel *wrappedChannel; + +@end + +/** Test-only interface for \a GRPCChannelPool. */ +@interface GRPCChannelPool (Test) + +/** + * Get an instance of pool isolated from the global shared pool with channels' destroy delay being + * \a destroyDelay. + */ +- (nullable instancetype)initTestPool; + +@end + + diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 7c6f2b3bbf..d1f28ec9bf 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -75,23 +75,6 @@ NS_ASSUME_NONNULL_BEGIN @end -/** Test-only interface for \a GRPCPooledChannel. */ -@interface GRPCPooledChannel (Test) - -/** - * Initialize a pooled channel with non-default destroy delay for testing purpose. - */ -- (nullable instancetype)initWithChannelConfiguration: -(GRPCChannelConfiguration *)channelConfiguration - destroyDelay:(NSTimeInterval)destroyDelay; - -/** - * Return the pointer to the raw channel wrapped. - */ -@property(atomic, readonly) GRPCChannel *wrappedChannel; - -@end - /** * Manage the pool of connected channels. When a channel is no longer referenced by any call, * destroy the channel after a certain period of time elapsed. @@ -119,15 +102,4 @@ NS_ASSUME_NONNULL_BEGIN @end -/** Test-only interface for \a GRPCChannelPool. */ -@interface GRPCChannelPool (Test) - -/** - * Get an instance of pool isolated from the global shared pool with channels' destroy delay being - * \a destroyDelay. - */ -- (nullable instancetype)initTestPool; - -@end - NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 391022efd1..349bdd44a6 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -22,6 +22,7 @@ #import "GRPCChannel.h" #import "GRPCChannelFactory.h" #import "GRPCChannelPool.h" +#import "GRPCChannelPool+Test.h" #import "GRPCConnectivityMonitor.h" #import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" @@ -59,9 +60,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; - (void)dealloc { // Disconnect GRPCWrappedCall objects created but not yet removed if (_wrappedCalls.allObjects.count != 0) { - NSEnumerator *enumerator = [_wrappedCalls objectEnumerator]; - GRPCWrappedCall *wrappedCall; - while ((wrappedCall = [enumerator nextObject])) { + for (GRPCWrappedCall *wrappedCall in _wrappedCalls.allObjects) { [wrappedCall channelDisconnected]; }; } @@ -73,7 +72,7 @@ callOptions:(GRPCCallOptions *)callOptions { NSAssert(path.length > 0, @"path must not be empty."); NSAssert(queue != nil, @"completionQueue must not be empty."); NSAssert(callOptions, @"callOptions must not be empty."); - if (path.length == 0 || queue == nil || callOptions == nil) return NULL; + if (path.length == 0 || queue == nil || callOptions == nil) return nil; GRPCWrappedCall *call = nil; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 287aa0369b..2e0400a323 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -28,6 +28,14 @@ NS_ASSUME_NONNULL_BEGIN /** An object can implement this protocol to receive responses from server from a call. */ @protocol GRPCProtoResponseHandler +@required + +/** + * All the responses must be issued to a user-provided dispatch queue. This property specifies the + * dispatch queue to be used for issuing the notifications. + */ +@property(atomic, readonly) dispatch_queue_t dispatchQueue; + @optional /** @@ -49,14 +57,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata error:(nullable NSError *)error; -@required - -/** - * All the responses must be issued to a user-provided dispatch queue. This property specifies the - * dispatch queue to be used for issuing the notifications. - */ -@property(atomic, readonly) dispatch_queue_t dispatchQueue; - @end /** A unary-request RPC call with Protobuf. */ diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 886e31ce58..0f63f72f53 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -75,7 +75,6 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (void)cancel { [_call cancel]; - _call = nil; } @end @@ -124,7 +123,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing #else { #endif - _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); } dispatch_set_target_queue(_dispatchQueue, handler.dispatchQueue); @@ -145,7 +144,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing copiedCall = _call; _call = nil; if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { - dispatch_async(_handler.dispatchQueue, ^{ + dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { copiedHandler = self->_handler; diff --git a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m index dc42d7c341..eab8c5193f 100644 --- a/src/objective-c/tests/ChannelTests/ChannelPoolTest.m +++ b/src/objective-c/tests/ChannelTests/ChannelPoolTest.m @@ -19,7 +19,7 @@ #import #import "../../GRPCClient/private/GRPCChannel.h" -#import "../../GRPCClient/private/GRPCChannelPool.h" +#import "../../GRPCClient/private/GRPCChannelPool+Test.h" #import "../../GRPCClient/private/GRPCCompletionQueue.h" #define TEST_TIMEOUT 32 diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index ee7f8b6fdd..7c80868c2c 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -21,6 +21,7 @@ #import "../../GRPCClient/GRPCCallOptions.h" #import "../../GRPCClient/private/GRPCChannel.h" #import "../../GRPCClient/private/GRPCChannelPool.h" +#import "../../GRPCClient/private/GRPCChannelPool+Test.h" #import "../../GRPCClient/private/GRPCCompletionQueue.h" #import "../../GRPCClient/private/GRPCWrappedCall.h" -- cgit v1.2.3 From da759f1fc63ceb0c893bb6027bacfadfda5ab111 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 6 Dec 2018 18:26:51 -0800 Subject: batch fixes --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/GRPCClient/GRPCCall.m | 5 +- src/objective-c/GRPCClient/GRPCCallOptions.h | 4 +- src/objective-c/GRPCClient/GRPCCallOptions.m | 32 ++++----- src/objective-c/GRPCClient/private/GRPCChannel.h | 5 +- src/objective-c/GRPCClient/private/GRPCChannel.m | 8 +-- .../GRPCClient/private/GRPCChannelPool.h | 13 ++-- .../GRPCClient/private/GRPCChannelPool.m | 82 ++++++++++++---------- .../GRPCClient/private/GRPCCronetChannelFactory.m | 8 +-- src/objective-c/GRPCClient/private/GRPCHost.m | 7 +- .../GRPCClient/private/GRPCSecureChannelFactory.m | 5 +- .../GRPCClient/private/GRPCWrappedCall.m | 11 +-- src/objective-c/GRPCClient/private/utilities.h | 22 ------ 13 files changed, 89 insertions(+), 115 deletions(-) delete mode 100644 src/objective-c/GRPCClient/private/utilities.h diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 6d8b9c1b12..be63de1af9 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -206,7 +206,7 @@ extern NSString *const kGRPCTrailersKey; @property(copy, readonly) NSString *path; /** * Specify whether the call is idempotent or cachable. gRPC may select different HTTP verbs for the - * call based on this information. + * call based on this information. The default verb used by gRPC is POST. */ @property(readonly) GRPCCallSafety safety; diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index e75ca7193a..e56cc72149 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -35,7 +35,6 @@ #import "private/NSData+GRPC.h" #import "private/NSDictionary+GRPC.h" #import "private/NSError+GRPC.h" -#import "private/utilities.h" #import "private/GRPCChannelPool.h" #import "private/GRPCCompletionQueue.h" @@ -277,7 +276,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)writeData:(NSData *)data { GRXBufferedPipe *copiedPipe = nil; @synchronized(self) { - NSAssert(!_canceled, @"Call arleady canceled."); + NSAssert(!_canceled, @"Call already canceled."); NSAssert(!_finished, @"Call is half-closed before sending data."); if (_canceled) { return; @@ -297,7 +296,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; GRXBufferedPipe *copiedPipe = nil; @synchronized(self) { NSAssert(_started, @"Call not started."); - NSAssert(!_canceled, @"Call arleady canceled."); + NSAssert(!_canceled, @"Call already canceled."); NSAssert(!_finished, @"Call already half-closed."); if (!_started) { return; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 158a4745d2..85786c7417 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -170,7 +170,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * PEM format certificate chain for client authentication, if required by the server. */ -@property(copy, readonly, nullable) NSString *PEMCertChain; +@property(copy, readonly, nullable) NSString *PEMCertificateChain; /** * Select the transport type to be used for this call. @@ -314,7 +314,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * PEM format certificate chain for client authentication, if required by the server. */ -@property(copy, readwrite, nullable) NSString *PEMCertChain; +@property(copy, readwrite, nullable) NSString *PEMCertificateChain; /** * Select the transport type to be used for this call. diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 9a36ee547c..1962ad8956 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -35,7 +35,7 @@ static const NSTimeInterval kDefaultConnectMaxBackoff = 0; static NSDictionary *const kDefaultAdditionalChannelArgs = nil; static NSString *const kDefaultPEMRootCertificates = nil; static NSString *const kDefaultPEMPrivateKey = nil; -static NSString *const kDefaultPEMCertChain = nil; +static NSString *const kDefaultPEMCertificateChain = nil; static NSString *const kDefaultOauth2AccessToken = nil; static const id kDefaultAuthTokenProvider = nil; static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2BoringSSL; @@ -74,7 +74,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { NSDictionary *_additionalChannelArgs; NSString *_PEMRootCertificates; NSString *_PEMPrivateKey; - NSString *_PEMCertChain; + NSString *_PEMCertificateChain; GRPCTransportType _transportType; NSString *_hostNameOverride; id _logContext; @@ -99,7 +99,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { @synthesize additionalChannelArgs = _additionalChannelArgs; @synthesize PEMRootCertificates = _PEMRootCertificates; @synthesize PEMPrivateKey = _PEMPrivateKey; -@synthesize PEMCertChain = _PEMCertChain; +@synthesize PEMCertificateChain = _PEMCertificateChain; @synthesize transportType = _transportType; @synthesize hostNameOverride = _hostNameOverride; @synthesize logContext = _logContext; @@ -124,7 +124,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:kDefaultAdditionalChannelArgs PEMRootCertificates:kDefaultPEMRootCertificates PEMPrivateKey:kDefaultPEMPrivateKey - PEMCertChain:kDefaultPEMCertChain + PEMCertificateChain:kDefaultPEMCertificateChain transportType:kDefaultTransportType hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext @@ -149,7 +149,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:(NSDictionary *)additionalChannelArgs PEMRootCertificates:(NSString *)PEMRootCertificates PEMPrivateKey:(NSString *)PEMPrivateKey - PEMCertChain:(NSString *)PEMCertChain + PEMCertificateChain:(NSString *)PEMCertificateChain transportType:(GRPCTransportType)transportType hostNameOverride:(NSString *)hostNameOverride logContext:(id)logContext @@ -174,7 +174,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; _PEMRootCertificates = [PEMRootCertificates copy]; _PEMPrivateKey = [PEMPrivateKey copy]; - _PEMCertChain = [PEMCertChain copy]; + _PEMCertificateChain = [PEMCertificateChain copy]; _transportType = transportType; _hostNameOverride = [hostNameOverride copy]; _logContext = logContext; @@ -203,7 +203,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:_additionalChannelArgs PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey - PEMCertChain:_PEMCertChain + PEMCertificateChain:_PEMCertificateChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -233,7 +233,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { copyItems:YES] PEMRootCertificates:[_PEMRootCertificates copy] PEMPrivateKey:[_PEMPrivateKey copy] - PEMCertChain:[_PEMCertChain copy] + PEMCertificateChain:[_PEMCertificateChain copy] transportType:_transportType hostNameOverride:[_hostNameOverride copy] logContext:_logContext @@ -256,7 +256,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { if (!areObjectsEqual(callOptions.additionalChannelArgs, _additionalChannelArgs)) return NO; if (!areObjectsEqual(callOptions.PEMRootCertificates, _PEMRootCertificates)) return NO; if (!areObjectsEqual(callOptions.PEMPrivateKey, _PEMPrivateKey)) return NO; - if (!areObjectsEqual(callOptions.PEMCertChain, _PEMCertChain)) return NO; + if (!areObjectsEqual(callOptions.PEMCertificateChain, _PEMCertificateChain)) return NO; if (!areObjectsEqual(callOptions.hostNameOverride, _hostNameOverride)) return NO; if (!(callOptions.transportType == _transportType)) return NO; if (!areObjectsEqual(callOptions.logContext, _logContext)) return NO; @@ -280,7 +280,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { result ^= _additionalChannelArgs.hash; result ^= _PEMRootCertificates.hash; result ^= _PEMPrivateKey.hash; - result ^= _PEMCertChain.hash; + result ^= _PEMCertificateChain.hash; result ^= _hostNameOverride.hash; result ^= _transportType; result ^= _logContext.hash; @@ -311,7 +311,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { @dynamic additionalChannelArgs; @dynamic PEMRootCertificates; @dynamic PEMPrivateKey; -@dynamic PEMCertChain; +@dynamic PEMCertificateChain; @dynamic transportType; @dynamic hostNameOverride; @dynamic logContext; @@ -336,7 +336,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:kDefaultAdditionalChannelArgs PEMRootCertificates:kDefaultPEMRootCertificates PEMPrivateKey:kDefaultPEMPrivateKey - PEMCertChain:kDefaultPEMCertChain + PEMCertificateChain:kDefaultPEMCertificateChain transportType:kDefaultTransportType hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext @@ -363,7 +363,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:_additionalChannelArgs PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey - PEMCertChain:_PEMCertChain + PEMCertificateChain:_PEMCertificateChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -391,7 +391,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:[_additionalChannelArgs copy] PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey - PEMCertChain:_PEMCertChain + PEMCertificateChain:_PEMCertificateChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -493,8 +493,8 @@ static BOOL areObjectsEqual(id obj1, id obj2) { _PEMPrivateKey = [PEMPrivateKey copy]; } -- (void)setPEMCertChain:(NSString *)PEMCertChain { - _PEMCertChain = [PEMCertChain copy]; +- (void)setPEMCertificateChain:(NSString *)PEMCertificateChain { + _PEMCertificateChain = [PEMCertificateChain copy]; } - (void)setTransportType:(GRPCTransportType)transportType { diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index c01aeccf81..bbada0d8cb 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -29,7 +29,10 @@ struct grpc_channel_credentials; NS_ASSUME_NONNULL_BEGIN -/** Caching signature of a channel. */ +/** + * Signature for the channel. If two channel's signatures are the same and connect to the same + * remote, they share the same underlying \a GRPCChannel object. + */ @interface GRPCChannelConfiguration : NSObject - (instancetype)init NS_UNAVAILABLE; diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 9432e7ab39..edcedf6e24 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -28,7 +28,6 @@ #import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" -#import "utilities.h" #import "version.h" #import @@ -63,8 +62,9 @@ factory = [GRPCSecureChannelFactory factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates privateKey:_callOptions.PEMPrivateKey - certChain:_callOptions.PEMCertChain + certChain:_callOptions.PEMCertificateChain error:&error]; + NSAssert(factory != nil, @"Failed to create secure channel factory"); if (factory == nil) { NSLog(@"Error creating secure channel factory: %@", error); } @@ -114,8 +114,8 @@ [NSNumber numberWithUnsignedInteger:(NSUInteger)(_callOptions.keepaliveTimeout * 1000)]; } - if (_callOptions.retryEnabled == NO) { - args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:_callOptions.retryEnabled]; + if (!_callOptions.retryEnabled) { + args[@GRPC_ARG_ENABLE_RETRIES] = [NSNumber numberWithInt:_callOptions.retryEnabled ? 1 : 0]; } if (_callOptions.connectMinTimeout > 0) { diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index d1f28ec9bf..19ef4c93ac 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -16,11 +16,6 @@ * */ -/** - * Signature for the channel. If two channel's signatures are the same, they share the same - * underlying \a GRPCChannel object. - */ - #import #import "GRPCChannelFactory.h" @@ -35,10 +30,10 @@ NS_ASSUME_NONNULL_BEGIN @class GRPCWrappedCall; /** - * A proxied channel object that can be retained and creates GRPCWrappedCall object from. If a - * raw channel is not present (i.e. no tcp connection to the server) when a GRPCWrappedCall object - * is requested, it issues a connection/reconnection. The behavior of this object is to mimic that - * of gRPC core's channel object. + * A proxied channel object that can be retained and used to create GRPCWrappedCall object + * regardless of the current connection status. If a connection is not established when a + * GRPCWrappedCall object is requested, it issues a connection/reconnection. This behavior is to + * follow that of gRPC core's channel object. */ @interface GRPCPooledChannel : NSObject diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 349bdd44a6..17c74e558b 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -27,7 +27,6 @@ #import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" -#import "utilities.h" #import "version.h" #import "GRPCWrappedCall.h" #import "GRPCCompletionQueue.h" @@ -57,6 +56,34 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; return [self initWithChannelConfiguration:channelConfiguration destroyDelay:kDefaultChannelDestroyDelay]; } +- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration + destroyDelay:(NSTimeInterval)destroyDelay { + NSAssert(channelConfiguration != nil, @"channelConfiguration cannot be empty."); + if (channelConfiguration == nil) { + return nil; + } + + if ((self = [super init])) { + _channelConfiguration = [channelConfiguration copy]; + _destroyDelay = destroyDelay; + _wrappedCalls = [NSHashTable weakObjectsHashTable]; + _wrappedChannel = nil; + _lastTimedDestroy = nil; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + if (@available(iOS 8.0, macOS 10.10, *)) { + _timerQueue = dispatch_queue_create(NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); + } else { +#else + { +#endif + _timerQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } + } + + return self; +} + - (void)dealloc { // Disconnect GRPCWrappedCall objects created but not yet removed if (_wrappedCalls.allObjects.count != 0) { @@ -67,12 +94,14 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } - (GRPCWrappedCall *)wrappedCallWithPath:(NSString *)path -completionQueue:(GRPCCompletionQueue *)queue -callOptions:(GRPCCallOptions *)callOptions { + completionQueue:(GRPCCompletionQueue *)queue + callOptions:(GRPCCallOptions *)callOptions { NSAssert(path.length > 0, @"path must not be empty."); NSAssert(queue != nil, @"completionQueue must not be empty."); NSAssert(callOptions, @"callOptions must not be empty."); - if (path.length == 0 || queue == nil || callOptions == nil) return nil; + if (path.length == 0 || queue == nil || callOptions == nil) { + return nil; + } GRPCWrappedCall *call = nil; @@ -97,6 +126,7 @@ callOptions:(GRPCCallOptions *)callOptions { call = [[GRPCWrappedCall alloc] initWithUnmanagedCall:unmanagedCall pooledChannel:self]; if (call == nil) { NSAssert(call != nil, @"Unable to create GRPCWrappedCall object"); + grpc_call_unref(unmanagedCall); return nil; } @@ -111,16 +141,22 @@ callOptions:(GRPCCallOptions *)callOptions { return; } @synchronized(self) { - // Detect if all objects weakly referenced in _wrappedCalls are (implicitly) removed. In such - // case the channel is no longer referenced by a grpc_call object and can be destroyed after - // a certain delay. + // Detect if all objects weakly referenced in _wrappedCalls are (implicitly) removed. + // _wrappedCalls.count does not work here since the hash table may include deallocated weak + // references. _wrappedCalls.allObjects forces removal of those objects. if (_wrappedCalls.allObjects.count == 0) { + // No more call has reference to this channel. We may start the timer for destroying the + // channel now. NSDate *now = [NSDate date]; NSAssert(now != nil, @"Unable to create NSDate object 'now'."); _lastTimedDestroy = now; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)_destroyDelay * NSEC_PER_SEC), _timerQueue, ^{ @synchronized(self) { + // Check _lastTimedDestroy against now in case more calls are created (and + // maybe destroyed) after this dispatch_async. In that case the current + // dispatch_after block should be discarded; the channel should be + // destroyed in a later dispatch_after block. if (now != nil && self->_lastTimedDestroy == now) { self->_wrappedChannel = nil; self->_lastTimedDestroy = nil; @@ -145,38 +181,6 @@ callOptions:(GRPCCallOptions *)callOptions { } } -@end - -@implementation GRPCPooledChannel (Test) - -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration - destroyDelay:(NSTimeInterval)destroyDelay { - NSAssert(channelConfiguration != nil, @"channelConfiguration cannot be empty."); - if (channelConfiguration == nil) { - return nil; - } - - if ((self = [super init])) { - _channelConfiguration = [channelConfiguration copy]; - _destroyDelay = destroyDelay; - _wrappedCalls = [NSHashTable weakObjectsHashTable]; - _wrappedChannel = nil; - _lastTimedDestroy = nil; -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - if (@available(iOS 8.0, macOS 10.10, *)) { - _timerQueue = dispatch_queue_create(NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); - } else { -#else - { -#endif - _timerQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } - } - - return self; -} - - (GRPCChannel *)wrappedChannel { GRPCChannel *channel = nil; @synchronized(self) { diff --git a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index 0aeb67b142..5bcb021dc4 100644 --- a/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -40,8 +40,8 @@ } - (instancetype)initWithEngine:(stream_engine *)engine { + NSAssert(engine != NULL, @"Cronet engine cannot be empty."); if (!engine) { - [NSException raise:NSInvalidArgumentException format:@"Cronet engine is NULL. Set it first."]; return nil; } if ((self = [super init])) { @@ -65,14 +65,12 @@ @implementation GRPCCronetChannelFactory + (instancetype)sharedInstance { - [NSException raise:NSInvalidArgumentException - format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; + NSAssert(NO, @"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."); return nil; } - (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { - [NSException raise:NSInvalidArgumentException - format:@"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."]; + NSAssert(NO, @"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."); return NULL; } diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 0f2281ede8..e7a7460221 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -32,7 +32,6 @@ #import "GRPCCronetChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "NSDictionary+GRPC.h" -#import "utilities.h" #import "version.h" NS_ASSUME_NONNULL_BEGIN @@ -42,7 +41,7 @@ static NSMutableDictionary *gHostCache; @implementation GRPCHost { NSString *_PEMRootCertificates; NSString *_PEMPrivateKey; - NSString *_pemCertChain; + NSString *_PEMCertificateChain; } + (nullable instancetype)hostWithAddress:(NSString *)address { @@ -96,7 +95,7 @@ static NSMutableDictionary *gHostCache; error:(NSError **)errorPtr { _PEMRootCertificates = [pemRootCerts copy]; _PEMPrivateKey = [pemPrivateKey copy]; - _pemCertChain = [pemCertChain copy]; + _PEMCertificateChain = [pemCertChain copy]; return YES; } @@ -113,7 +112,7 @@ static NSMutableDictionary *gHostCache; options.connectMaxBackoff = (NSTimeInterval)_maxConnectBackoff / 1000; options.PEMRootCertificates = _PEMRootCertificates; options.PEMPrivateKey = _PEMPrivateKey; - options.PEMCertChain = _pemCertChain; + options.PEMCertificateChain = _PEMCertificateChain; options.hostNameOverride = _hostNameOverride; #ifdef GRPC_COMPILE_WITH_CRONET // By old API logic, insecure channel precedes Cronet channel; Cronet channel preceeds default diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 69f70de17d..3ccc70a744 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -22,7 +22,6 @@ #import "ChannelArgsUtil.h" #import "GRPCChannel.h" -#import "utilities.h" @implementation GRPCSecureChannelFactory { grpc_channel_credentials *_channelCreds; @@ -116,6 +115,10 @@ } - (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { + NSAssert(host.length != 0, @"host cannot be empty"); + if (host.length == 0) { + return NULL; + } grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 727c9e0a88..82149e3dba 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -30,7 +30,6 @@ #import "NSData+GRPC.h" #import "NSDictionary+GRPC.h" #import "NSError+GRPC.h" -#import "utilities.h" #import "GRPCOpBatchLog.h" @@ -237,6 +236,7 @@ #pragma mark GRPCWrappedCall @implementation GRPCWrappedCall { + // pooledChannel holds weak reference to this object so this is ok GRPCPooledChannel *_pooledChannel; grpc_call *_call; } @@ -275,8 +275,7 @@ for (GRPCOperation *operation in operations) { ops_array[i++] = operation.op; } - grpc_call_error error; - error = grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(bool success) { + grpc_call_error error = grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(bool success) { if (!success) { if (errorHandler) { errorHandler(); @@ -291,11 +290,7 @@ NULL); gpr_free(ops_array); - if (error != GRPC_CALL_OK) { - [NSException - raise:NSInternalInconsistencyException - format:@"A precondition for calling grpc_call_start_batch wasn't met. Error %i", error]; - } + NSAssert(error == GRPC_CALL_OK, @"Error starting a batch of operations: %i", error); } } } diff --git a/src/objective-c/GRPCClient/private/utilities.h b/src/objective-c/GRPCClient/private/utilities.h deleted file mode 100644 index 8e3dd79358..0000000000 --- a/src/objective-c/GRPCClient/private/utilities.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import - -/** Raise exception when condition not met. */ -#define GRPCAssert(condition, errorString) NSAssert(condition, errorString) -- cgit v1.2.3 From 1a9404876ce0315fc05fe82465dc389600db0965 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 6 Dec 2018 19:07:25 -0800 Subject: batch fixes --- src/objective-c/GRPCClient/private/GRPCChannel.m | 16 ++++++---------- src/objective-c/GRPCClient/private/GRPCHost.m | 2 +- src/objective-c/ProtoRPC/ProtoRPC.m | 15 ++++++++------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index edcedf6e24..12acfa1429 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -50,16 +50,17 @@ } - (id)channelFactory { - NSError *error; - id factory; GRPCTransportType type = _callOptions.transportType; switch (type) { case GRPCTransportTypeChttp2BoringSSL: // TODO (mxyan): Remove when the API is deprecated #ifdef GRPC_COMPILE_WITH_CRONET if (![GRPCCall isUsingCronet]) { +#else + { #endif - factory = [GRPCSecureChannelFactory + NSError *error; + id factory = [GRPCSecureChannelFactory factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates privateKey:_callOptions.PEMPrivateKey certChain:_callOptions.PEMCertificateChain @@ -69,9 +70,7 @@ NSLog(@"Error creating secure channel factory: %@", error); } return factory; -#ifdef GRPC_COMPILE_WITH_CRONET } -#endif // fallthrough case GRPCTransportTypeCronet: return [GRPCCronetChannelFactory sharedInstance]; @@ -164,7 +163,7 @@ } - (NSUInteger)hash { - NSUInteger result = 0; + NSUInteger result = 31; result ^= _host.hash; result ^= _callOptions.channelOptionsHash; @@ -230,10 +229,7 @@ NSTimeInterval timeout = callOptions.timeout; NSAssert(timeout >= 0, @"Invalid timeout"); if (timeout < 0) return NULL; - grpc_slice host_slice = grpc_empty_slice(); - if (serverAuthority) { - host_slice = grpc_slice_from_copied_string(serverAuthority.UTF8String); - } + grpc_slice host_slice = serverAuthority ? grpc_slice_from_copied_string(serverAuthority.UTF8String) : grpc_empty_slice(); grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); gpr_timespec deadline_ms = timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index e7a7460221..24348c3aed 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -75,7 +75,7 @@ static NSMutableDictionary *gHostCache; } if ((self = [super init])) { - _address = address; + _address = [address copy]; _retryEnabled = YES; gHostCache[address] = self; } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 0f63f72f53..89f0b3f347 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -97,14 +97,13 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { - if (requestOptions.host.length == 0 || requestOptions.path.length == 0) { - [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."]; - } - if (requestOptions.safety > GRPCCallSafetyCacheableRequest) { - [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."]; + NSAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0 && requestOptions.safety <= GRPCCallSafetyCacheableRequest, @"Invalid callOptions."); + NSAssert(handler != nil, @"handler cannot be empty."); + if (requestOptions.host.length == 0 || requestOptions.path.length == 0 || requestOptions.safety > GRPCCallSafetyCacheableRequest) { + return nil; } if (handler == nil) { - [NSException raise:NSInvalidArgumentException format:@"Response handler required."]; + return nil; } if ((self = [super init])) { @@ -166,8 +165,10 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)writeMessage:(GPBMessage *)message { + NSAssert([message isKindOfClass:[GPBMessage class]]); if (![message isKindOfClass:[GPBMessage class]]) { - [NSException raise:NSInvalidArgumentException format:@"Data must be a valid protobuf type."]; + NSLog(@"Failed to send a message that is non-proto."); + return; } GRPCCall2 *call; -- cgit v1.2.3 From f0f6e03212837c67d7e078e6f33074e80aa4bcc0 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 6 Dec 2018 22:41:03 -0800 Subject: clang-format --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/GRPCClient/GRPCCall.m | 19 +++--- src/objective-c/GRPCClient/GRPCCallOptions.m | 8 +-- src/objective-c/GRPCClient/private/GRPCChannel.m | 6 +- .../GRPCClient/private/GRPCChannelPool+Test.h | 4 +- .../GRPCClient/private/GRPCChannelPool.h | 2 +- .../GRPCClient/private/GRPCChannelPool.m | 26 ++++---- .../GRPCClient/private/GRPCWrappedCall.h | 2 +- .../GRPCClient/private/GRPCWrappedCall.m | 35 ++++++----- src/objective-c/ProtoRPC/ProtoRPC.m | 24 ++++--- src/objective-c/tests/ChannelTests/ChannelTests.m | 49 ++++++--------- src/objective-c/tests/InteropTests.m | 73 ++++++++++++---------- 12 files changed, 127 insertions(+), 123 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index be63de1af9..b549f5d2bf 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -181,7 +181,7 @@ extern NSString *const kGRPCTrailersKey; * error descriptions. */ - (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata - error:(nullable NSError *)error; + error:(nullable NSError *)error; @end diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index e56cc72149..589b52031a 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -28,6 +28,8 @@ #include #import "GRPCCallOptions.h" +#import "private/GRPCChannelPool.h" +#import "private/GRPCCompletionQueue.h" #import "private/GRPCConnectivityMonitor.h" #import "private/GRPCHost.h" #import "private/GRPCRequestHeaders.h" @@ -35,8 +37,6 @@ #import "private/NSData+GRPC.h" #import "private/NSDictionary+GRPC.h" #import "private/NSError+GRPC.h" -#import "private/GRPCChannelPool.h" -#import "private/GRPCCompletionQueue.h" // At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA, // SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE, @@ -259,12 +259,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; } [copiedHandler didCloseWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; }); } else { _handler = nil; @@ -819,7 +819,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; - GRPCPooledChannel *channel = [[GRPCChannelPool sharedInstance] channelWithHost:_host callOptions:_callOptions]; + GRPCPooledChannel *channel = + [[GRPCChannelPool sharedInstance] channelWithHost:_host callOptions:_callOptions]; GRPCWrappedCall *wrappedCall = [channel wrappedCallWithPath:_path completionQueue:[GRPCCompletionQueue completionQueue] callOptions:_callOptions]; diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 1962ad8956..d3440ee6c0 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -233,7 +233,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { copyItems:YES] PEMRootCertificates:[_PEMRootCertificates copy] PEMPrivateKey:[_PEMPrivateKey copy] - PEMCertificateChain:[_PEMCertificateChain copy] + PEMCertificateChain:[_PEMCertificateChain copy] transportType:_transportType hostNameOverride:[_hostNameOverride copy] logContext:_logContext @@ -336,7 +336,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:kDefaultAdditionalChannelArgs PEMRootCertificates:kDefaultPEMRootCertificates PEMPrivateKey:kDefaultPEMPrivateKey - PEMCertificateChain:kDefaultPEMCertificateChain + PEMCertificateChain:kDefaultPEMCertificateChain transportType:kDefaultTransportType hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext @@ -363,7 +363,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:_additionalChannelArgs PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey - PEMCertificateChain:_PEMCertificateChain + PEMCertificateChain:_PEMCertificateChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext @@ -391,7 +391,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { additionalChannelArgs:[_additionalChannelArgs copy] PEMRootCertificates:_PEMRootCertificates PEMPrivateKey:_PEMPrivateKey - PEMCertificateChain:_PEMCertificateChain + PEMCertificateChain:_PEMCertificateChain transportType:_transportType hostNameOverride:_hostNameOverride logContext:_logContext diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 12acfa1429..1a79fb04a0 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -57,7 +57,7 @@ #ifdef GRPC_COMPILE_WITH_CRONET if (![GRPCCall isUsingCronet]) { #else - { + { #endif NSError *error; id factory = [GRPCSecureChannelFactory @@ -229,7 +229,9 @@ NSTimeInterval timeout = callOptions.timeout; NSAssert(timeout >= 0, @"Invalid timeout"); if (timeout < 0) return NULL; - grpc_slice host_slice = serverAuthority ? grpc_slice_from_copied_string(serverAuthority.UTF8String) : grpc_empty_slice(); + grpc_slice host_slice = serverAuthority + ? grpc_slice_from_copied_string(serverAuthority.UTF8String) + : grpc_empty_slice(); grpc_slice path_slice = grpc_slice_from_copied_string(path.UTF8String); gpr_timespec deadline_ms = timeout == 0 ? gpr_inf_future(GPR_CLOCK_REALTIME) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h b/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h index 4e7c988585..ca0cc51a52 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h @@ -25,7 +25,7 @@ * Initialize a pooled channel with non-default destroy delay for testing purpose. */ - (nullable instancetype)initWithChannelConfiguration: -(GRPCChannelConfiguration *)channelConfiguration + (GRPCChannelConfiguration *)channelConfiguration destroyDelay:(NSTimeInterval)destroyDelay; /** @@ -45,5 +45,3 @@ - (nullable instancetype)initTestPool; @end - - diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index 19ef4c93ac..d3a99ca826 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -45,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN * Initialize with an actual channel object \a channel and a reference to the channel pool. */ - (nullable instancetype)initWithChannelConfiguration: - (GRPCChannelConfiguration *)channelConfiguration; + (GRPCChannelConfiguration *)channelConfiguration; /** * Create a GRPCWrappedCall object (grpc_call) from this channel. If channel is disconnected, get a diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m index 17c74e558b..a323f0490c 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -21,15 +21,15 @@ #import "../internal/GRPCCallOptions+Internal.h" #import "GRPCChannel.h" #import "GRPCChannelFactory.h" -#import "GRPCChannelPool.h" #import "GRPCChannelPool+Test.h" +#import "GRPCChannelPool.h" +#import "GRPCCompletionQueue.h" #import "GRPCConnectivityMonitor.h" #import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" -#import "version.h" #import "GRPCWrappedCall.h" -#import "GRPCCompletionQueue.h" +#import "version.h" #import #include @@ -53,10 +53,12 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } - (instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration { - return [self initWithChannelConfiguration:channelConfiguration destroyDelay:kDefaultChannelDestroyDelay]; + return [self initWithChannelConfiguration:channelConfiguration + destroyDelay:kDefaultChannelDestroyDelay]; } -- (nullable instancetype)initWithChannelConfiguration:(GRPCChannelConfiguration *)channelConfiguration +- (nullable instancetype)initWithChannelConfiguration: + (GRPCChannelConfiguration *)channelConfiguration destroyDelay:(NSTimeInterval)destroyDelay { NSAssert(channelConfiguration != nil, @"channelConfiguration cannot be empty."); if (channelConfiguration == nil) { @@ -71,8 +73,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; _lastTimedDestroy = nil; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 if (@available(iOS 8.0, macOS 10.10, *)) { - _timerQueue = dispatch_queue_create(NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); + _timerQueue = dispatch_queue_create(NULL, dispatch_queue_attr_make_with_qos_class( + DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); } else { #else { @@ -115,9 +117,10 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; } _lastTimedDestroy = nil; - grpc_call *unmanagedCall = [_wrappedChannel unmanagedCallWithPath:path - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:callOptions]; + grpc_call *unmanagedCall = + [_wrappedChannel unmanagedCallWithPath:path + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:callOptions]; if (unmanagedCall == NULL) { NSAssert(unmanagedCall != NULL, @"Unable to create grpc_call object"); return nil; @@ -203,8 +206,7 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30; + (instancetype)sharedInstance { dispatch_once(&gInitChannelPool, ^{ - gChannelPool = - [[GRPCChannelPool alloc] initPrivate]; + gChannelPool = [[GRPCChannelPool alloc] initPrivate]; NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool."); }); return gChannelPool; diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h index 0432190528..92bd1be257 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h @@ -77,7 +77,7 @@ - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)new NS_UNAVAILABLE; ++ (instancetype) new NS_UNAVAILABLE; - (instancetype)initWithUnmanagedCall:(grpc_call *)unmanagedCall pooledChannel:(GRPCPooledChannel *)pooledChannel NS_DESIGNATED_INITIALIZER; diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 82149e3dba..9066cb950f 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -267,7 +267,7 @@ [GRPCOpBatchLog addOpBatchToLog:operations]; #endif - @synchronized (self) { + @synchronized(self) { if (_call != NULL) { size_t nops = operations.count; grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op)); @@ -275,19 +275,20 @@ for (GRPCOperation *operation in operations) { ops_array[i++] = operation.op; } - grpc_call_error error = grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(bool success) { - if (!success) { - if (errorHandler) { - errorHandler(); - } else { - return; - } - } - for (GRPCOperation *operation in operations) { - [operation finish]; - } - }), - NULL); + grpc_call_error error = + grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(bool success) { + if (!success) { + if (errorHandler) { + errorHandler(); + } else { + return; + } + } + for (GRPCOperation *operation in operations) { + [operation finish]; + } + }), + NULL); gpr_free(ops_array); NSAssert(error == GRPC_CALL_OK, @"Error starting a batch of operations: %i", error); @@ -296,7 +297,7 @@ } - (void)cancel { - @synchronized (self) { + @synchronized(self) { if (_call != NULL) { grpc_call_cancel(_call, NULL); } @@ -304,7 +305,7 @@ } - (void)channelDisconnected { - @synchronized (self) { + @synchronized(self) { if (_call != NULL) { grpc_call_unref(_call); _call = NULL; @@ -313,7 +314,7 @@ } - (void)dealloc { - @synchronized (self) { + @synchronized(self) { if (_call != NULL) { grpc_call_unref(_call); _call = NULL; diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 89f0b3f347..da53435178 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -97,9 +97,12 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { - NSAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0 && requestOptions.safety <= GRPCCallSafetyCacheableRequest, @"Invalid callOptions."); + NSAssert(requestOptions.host.length != 0 && requestOptions.path.length != 0 && + requestOptions.safety <= GRPCCallSafetyCacheableRequest, + @"Invalid callOptions."); NSAssert(handler != nil, @"handler cannot be empty."); - if (requestOptions.host.length == 0 || requestOptions.path.length == 0 || requestOptions.safety > GRPCCallSafetyCacheableRequest) { + if (requestOptions.host.length == 0 || requestOptions.path.length == 0 || + requestOptions.safety > GRPCCallSafetyCacheableRequest) { return nil; } if (handler == nil) { @@ -150,12 +153,12 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing self->_handler = nil; } [copiedHandler didCloseWithTrailingMetadata:nil - error:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; }); } else { _handler = nil; @@ -223,8 +226,9 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing copiedHandler = self->_handler; self->_handler = nil; } - [copiedHandler didCloseWithTrailingMetadata:nil - error:ErrorForBadProto(message, _responseClass, error)]; + [copiedHandler + didCloseWithTrailingMetadata:nil + error:ErrorForBadProto(message, _responseClass, error)]; }); [_call cancel]; _call = nil; diff --git a/src/objective-c/tests/ChannelTests/ChannelTests.m b/src/objective-c/tests/ChannelTests/ChannelTests.m index 7c80868c2c..df78e8b116 100644 --- a/src/objective-c/tests/ChannelTests/ChannelTests.m +++ b/src/objective-c/tests/ChannelTests/ChannelTests.m @@ -20,8 +20,8 @@ #import "../../GRPCClient/GRPCCallOptions.h" #import "../../GRPCClient/private/GRPCChannel.h" -#import "../../GRPCClient/private/GRPCChannelPool.h" #import "../../GRPCClient/private/GRPCChannelPool+Test.h" +#import "../../GRPCClient/private/GRPCChannelPool.h" #import "../../GRPCClient/private/GRPCCompletionQueue.h" #import "../../GRPCClient/private/GRPCWrappedCall.h" @@ -40,13 +40,12 @@ static NSString *kDummyPath = @"/dummy/path"; - (void)testPooledChannelCreatingChannel { GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCChannelConfiguration *config = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost - callOptions:options]; + GRPCChannelConfiguration *config = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options]; GRPCPooledChannel *channel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:config]; GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - GRPCWrappedCall *wrappedCall = [channel wrappedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + GRPCWrappedCall *wrappedCall = + [channel wrappedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); (void)wrappedCall; } @@ -54,26 +53,22 @@ static NSString *kDummyPath = @"/dummy/path"; - (void)testTimedDestroyChannel { const NSTimeInterval kDestroyDelay = 1.0; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCChannelConfiguration *config = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost - callOptions:options]; - GRPCPooledChannel *channel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:config - destroyDelay:kDestroyDelay]; + GRPCChannelConfiguration *config = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options]; + GRPCPooledChannel *channel = + [[GRPCPooledChannel alloc] initWithChannelConfiguration:config destroyDelay:kDestroyDelay]; GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; GRPCWrappedCall *wrappedCall; GRPCChannel *wrappedChannel; @autoreleasepool { - wrappedCall = [channel wrappedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + wrappedCall = [channel wrappedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); // Unref and ref channel immediately; expect using the same raw channel. wrappedChannel = channel.wrappedChannel; wrappedCall = nil; - wrappedCall = [channel wrappedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + wrappedCall = [channel wrappedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertEqual(channel.wrappedChannel, wrappedChannel); // Unref and ref channel after destroy delay; expect a new raw channel. @@ -81,23 +76,20 @@ static NSString *kDummyPath = @"/dummy/path"; } sleep(kDestroyDelay + 1); XCTAssertNil(channel.wrappedChannel); - wrappedCall = [channel wrappedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + wrappedCall = [channel wrappedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotEqual(channel.wrappedChannel, wrappedChannel); } - (void)testDisconnect { const NSTimeInterval kDestroyDelay = 1.0; GRPCCallOptions *options = [[GRPCCallOptions alloc] init]; - GRPCChannelConfiguration *config = [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost - callOptions:options]; - GRPCPooledChannel *channel = [[GRPCPooledChannel alloc] initWithChannelConfiguration:config - destroyDelay:kDestroyDelay]; + GRPCChannelConfiguration *config = + [[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options]; + GRPCPooledChannel *channel = + [[GRPCPooledChannel alloc] initWithChannelConfiguration:config destroyDelay:kDestroyDelay]; GRPCCompletionQueue *cq = [GRPCCompletionQueue completionQueue]; - GRPCWrappedCall *wrappedCall = [channel wrappedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + GRPCWrappedCall *wrappedCall = + [channel wrappedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); // Disconnect; expect wrapped channel to be dropped @@ -106,9 +98,8 @@ static NSString *kDummyPath = @"/dummy/path"; // Create a new call and unref the old call; confirm that destroy of the old call does not make // the channel disconnect, even after the destroy delay. - GRPCWrappedCall *wrappedCall2 = [channel wrappedCallWithPath:kDummyPath - completionQueue:cq - callOptions:options]; + GRPCWrappedCall *wrappedCall2 = + [channel wrappedCallWithPath:kDummyPath completionQueue:cq callOptions:options]; XCTAssertNotNil(channel.wrappedChannel); GRPCChannel *wrappedChannel = channel.wrappedChannel; wrappedCall = nil; diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index d17a07f929..3665e9705d 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -249,8 +249,10 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testLargeUnaryRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectRecvMessage = [self expectationWithDescription:@"LargeUnaryWithV2API received message"]; - __weak XCTestExpectation *expectRecvComplete = [self expectationWithDescription:@"LargeUnaryWithV2API received complete"]; + __weak XCTestExpectation *expectRecvMessage = + [self expectationWithDescription:@"LargeUnaryWithV2API received message"]; + __weak XCTestExpectation *expectRecvComplete = + [self expectationWithDescription:@"LargeUnaryWithV2API received complete"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; request.responseType = RMTPayloadType_Compressable; @@ -263,24 +265,26 @@ BOOL isRemoteInteropTest(NSString *host) { options.hostNameOverride = [[self class] hostNameOverride]; GRPCUnaryProtoCall *call = [_service - unaryCallWithMessage:request - responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil - messageCallback:^(id message) { - XCTAssertNotNil(message); - if (message) { - RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; - expectedResponse.payload.type = RMTPayloadType_Compressable; - expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; - XCTAssertEqualObjects(message, expectedResponse); - - [expectRecvMessage fulfill]; - } - } - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - XCTAssertNil(error, @"Unexpected error: %@", error); - [expectRecvComplete fulfill]; - }] - callOptions:options]; + unaryCallWithMessage:request + responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + XCTAssertNotNil(message); + if (message) { + RMTSimpleResponse *expectedResponse = + [RMTSimpleResponse message]; + expectedResponse.payload.type = RMTPayloadType_Compressable; + expectedResponse.payload.body = + [NSMutableData dataWithLength:314159]; + XCTAssertEqualObjects(message, expectedResponse); + + [expectRecvMessage fulfill]; + } + } + closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { + XCTAssertNil(error, @"Unexpected error: %@", error); + [expectRecvComplete fulfill]; + }] + callOptions:options]; [call start]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -602,7 +606,8 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testCancelAfterBeginRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBeginWithV2API"]; + __weak XCTestExpectation *expectation = + [self expectationWithDescription:@"CancelAfterBeginWithV2API"]; // A buffered pipe to which we never write any value acts as a writer that just hangs. __block GRPCStreamingProtoCall *call = [_service @@ -699,7 +704,7 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testCancelAfterFirstRequestWithV2API { XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *completionExpectation = - [self expectationWithDescription:@"Call completed."]; + [self expectationWithDescription:@"Call completed."]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.transportType = self.class.transportType; @@ -707,20 +712,20 @@ BOOL isRemoteInteropTest(NSString *host) { options.hostNameOverride = [[self class] hostNameOverride]; id request = - [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 requestedResponseSize:@31415]; + [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 requestedResponseSize:@31415]; __block GRPCStreamingProtoCall *call = [_service - fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] - initWithInitialMetadataCallback:nil - messageCallback:^(id message) { - XCTFail(@"Received unexpected response."); - } - closeCallback:^(NSDictionary *trailingMetadata, - NSError *error) { - XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); - [completionExpectation fulfill]; - }] - callOptions:options]; + fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] + initWithInitialMetadataCallback:nil + messageCallback:^(id message) { + XCTFail(@"Received unexpected response."); + } + closeCallback:^(NSDictionary *trailingMetadata, + NSError *error) { + XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); + [completionExpectation fulfill]; + }] + callOptions:options]; [call start]; [call writeMessage:request]; [call cancel]; -- cgit v1.2.3 From 92db5fc72488f9d62b81ee311a79832df787f3ef Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 7 Dec 2018 10:29:24 -0800 Subject: Rename getTokenWithHandler --- src/objective-c/GRPCClient/GRPCCall.m | 14 ++++++++++++-- src/objective-c/GRPCClient/GRPCCallOptions.h | 13 ++++++++++++- src/objective-c/ProtoRPC/ProtoRPC.m | 2 +- src/objective-c/tests/APIv2Tests/APIv2Tests.m | 2 +- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 589b52031a..18f79311a6 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -885,7 +885,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; @synchronized(self) { self.isWaitingForToken = YES; } - [_callOptions.authTokenProvider getTokenWithHandler:^(NSString *token) { + void (^tokenHandler)(NSString *token) = ^(NSString *token) { @synchronized(self) { if (self.isWaitingForToken) { if (token) { @@ -895,7 +895,17 @@ const char *kCFStreamVarName = "grpc_cfstream"; self.isWaitingForToken = NO; } } - }]; + }; + id authTokenProvider = _callOptions.authTokenProvider; + if ([authTokenProvider respondsToSelector:@selector(provideTokenToHandler:)]) { + [_callOptions.authTokenProvider provideTokenToHandler:tokenHandler]; + } else { + NSAssert([authTokenProvider respondsToSelector:@selector(getTokenWithHandler:)], + @"authTokenProvider has no usable method"); + if ([authTokenProvider respondsToSelector:@selector(getTokenWithHandler:)]) { + [_callOptions.authTokenProvider getTokenWithHandler:tokenHandler]; + } + } } else { [self startCallWithWriteable:writeable]; } diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index 85786c7417..b7f08480dc 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -58,13 +58,24 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * Implement this protocol to provide a token to gRPC when a call is initiated. */ -@protocol GRPCAuthorizationProtocol +@protocol GRPCAuthorizationProtocol + +@optional + +/** + * This method is called when gRPC is about to start the call. When OAuth token is acquired, + * \a handler is expected to be called with \a token being the new token to be used for this call. + */ +- (void)provideTokenToHandler:(void (^_Nullable)(NSString *_Nullable token))handler; /** + * This method is deprecated. Please use \a provideTokenToHandler. + * * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ - (void)getTokenWithHandler:(void (^_Nullable)(NSString *_Nullable token))handler; + @end @interface GRPCCallOptions : NSObject diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index da53435178..92d7fce33c 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -168,7 +168,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)writeMessage:(GPBMessage *)message { - NSAssert([message isKindOfClass:[GPBMessage class]]); + NSAssert([message isKindOfClass:[GPBMessage class]], @"Parameter message must be a GPBMessage"); if (![message isKindOfClass:[GPBMessage class]]) { NSLog(@"Failed to send a message that is non-proto."); return; diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index ca7bf47283..fd472aafeb 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -241,7 +241,7 @@ static const NSTimeInterval kTestTimeout = 16; [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; } -- (void)getTokenWithHandler:(void (^)(NSString *token))handler { +- (void)provideTokenToHandler:(void (^)(NSString *token))handler { dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); dispatch_sync(queue, ^{ handler(@"test-access-token"); -- cgit v1.2.3 From df21aab3a6af360cff29a5164f9728ba646d35ab Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 7 Dec 2018 16:01:23 -0800 Subject: nullability annotation --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/ProtoRPC/ProtoRPC.h | 18 ++++++++--------- src/objective-c/ProtoRPC/ProtoRPC.m | 3 +++ src/objective-c/ProtoRPC/ProtoService.h | 34 ++++++++++++++++++--------------- src/objective-c/ProtoRPC/ProtoService.m | 7 ++++--- src/objective-c/tests/GRPCClientTests.m | 3 ++- 6 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 18f79311a6..cfd0de1a8a 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -485,7 +485,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. - NSAssert(host != nil && path != nil, @"Neither host nor path can be nil."); + NSAssert(host.length != 0 && path.length != 0, @"Neither host nor path can be nil."); NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); NSAssert(requestWriter.state == GRXWriterStateNotStarted, @"The requests writer can't be already started."); diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 2e0400a323..e6ba1f66ca 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -70,11 +70,11 @@ NS_ASSUME_NONNULL_BEGIN * Users should not use this initializer directly. Call objects will be created, initialized, and * returned to users by methods of the generated service. */ -- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - message:(GPBMessage *)message - responseHandler:(id)handler - callOptions:(nullable GRPCCallOptions *)callOptions - responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + message:(GPBMessage *)message + responseHandler:(id)handler + callOptions:(nullable GRPCCallOptions *)callOptions + responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** * Start the call. This function must only be called once for each instance. @@ -101,10 +101,10 @@ NS_ASSUME_NONNULL_BEGIN * Users should not use this initializer directly. Call objects will be created, initialized, and * returned to users by methods of the generated service. */ -- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions - responseHandler:(id)handler - callOptions:(nullable GRPCCallOptions *)callOptions - responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions + responseHandler:(id)handler + callOptions:(nullable GRPCCallOptions *)callOptions + responseClass:(Class)responseClass NS_DESIGNATED_INITIALIZER; /** * Start the call. This function must only be called once for each instance. diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 92d7fce33c..15b0f681ce 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -57,6 +57,9 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing responseClass:(Class)responseClass { NSAssert(message != nil, @"message cannot be empty."); NSAssert(responseClass != nil, @"responseClass cannot be empty."); + if (message == nil || responseClass == nil) { + return nil; + } if ((self = [super init])) { _call = [[GRPCStreamingProtoCall alloc] initWithRequestOptions:requestOptions responseHandler:handler diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index 2105de78a3..70423ee9de 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -27,33 +27,35 @@ @class GRPCStreamingProtoCall; @protocol GRPCProtoResponseCallbacks; +NS_ASSUME_NONNULL_BEGIN + __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoService : NSObject - - (instancetype)initWithHost : (NSString *)host packageName + (nullable instancetype)initWithHost : (NSString *)host packageName : (NSString *)packageName serviceName : (NSString *)serviceName callOptions - : (GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; + : (nullable GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; - (instancetype)initWithHost:(NSString *)host packageName:(NSString *)packageName serviceName:(NSString *)serviceName; -- (GRPCProtoCall *)RPCToMethod:(NSString *)method - requestsWriter:(GRXWriter *)requestsWriter - responseClass:(Class)responseClass - responsesWriteable:(id)responsesWriteable; +- (nullable GRPCProtoCall *)RPCToMethod:(NSString *)method + requestsWriter:(GRXWriter *)requestsWriter + responseClass:(Class)responseClass + responsesWriteable:(id)responsesWriteable; -- (GRPCUnaryProtoCall *)RPCToMethod:(NSString *)method - message:(id)message - responseHandler:(id)handler - callOptions:(GRPCCallOptions *)callOptions - responseClass:(Class)responseClass; +- (nullable GRPCUnaryProtoCall *)RPCToMethod:(NSString *)method + message:(id)message + responseHandler:(id)handler + callOptions:(nullable GRPCCallOptions *)callOptions + responseClass:(Class)responseClass; -- (GRPCStreamingProtoCall *)RPCToMethod:(NSString *)method - responseHandler:(id)handler - callOptions:(GRPCCallOptions *)callOptions - responseClass:(Class)responseClass; +- (nullable GRPCStreamingProtoCall *)RPCToMethod:(NSString *)method + responseHandler:(id)handler + callOptions:(nullable GRPCCallOptions *)callOptions + responseClass:(Class)responseClass; @end @@ -67,3 +69,5 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoServ #pragma clang diagnostic pop @end + + NS_ASSUME_NONNULL_END diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m index 6df502fb0c..3d998bfaeb 100644 --- a/src/objective-c/ProtoRPC/ProtoService.m +++ b/src/objective-c/ProtoRPC/ProtoService.m @@ -44,9 +44,10 @@ packageName:(NSString *)packageName serviceName:(NSString *)serviceName callOptions:(GRPCCallOptions *)callOptions { - if (!host || !serviceName) { - [NSException raise:NSInvalidArgumentException - format:@"Neither host nor serviceName can be nil."]; + NSAssert(host.length != 0 && packageName.length != 0 && serviceName.length != 0, + @"Invalid parameter."); + if (host.length == 0 || packageName.length == 0 || serviceName.length == 0) { + return nil; } if ((self = [super init])) { _host = [host copy]; diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 2cfdd1a003..b16720557f 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -362,9 +362,10 @@ static GRPCProtoMethod *kFullDuplexCallMethod; // TODO(makarandd): Move to a different file that contains only unit tests - (void)testExceptions { + GRXWriter *writer = [GRXWriter writerWithValue:[NSData data]]; // Try to set parameters to nil for GRPCCall. This should cause an exception @try { - (void)[[GRPCCall alloc] initWithHost:nil path:nil requestsWriter:nil]; + (void)[[GRPCCall alloc] initWithHost:@"" path:@"" requestsWriter:writer]; XCTFail(@"Did not receive an exception when parameters are nil"); } @catch (NSException *theException) { NSLog(@"Received exception as expected: %@", theException.name); -- cgit v1.2.3 From 3f00d61b04874cc5f0159c16f2c598a8f2fb93a7 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 7 Dec 2018 16:12:00 -0800 Subject: batch fix --- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 1 + src/objective-c/ProtoRPC/ProtoRPC.m | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 9066cb950f..4edd9d3e37 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -320,6 +320,7 @@ _call = NULL; } } + // Explicitly converting weak reference _pooledChannel to strong. __strong GRPCPooledChannel *channel = _pooledChannel; [channel notifyWrappedCallDealloc:self]; } diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 15b0f681ce..abf224c3cf 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -140,7 +140,11 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)start { - [_call start]; + GRPCCall2 *copiedCall; + @synchronized(self) { + copiedCall = _call; + } + [copiedCall start]; } - (void)cancel { @@ -177,20 +181,20 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing return; } - GRPCCall2 *call; + GRPCCall2 *copiedCall; @synchronized(self) { - call = _call; + copiedCall = _call; } - [call writeData:[message data]]; + [copiedCall writeData:[message data]]; } - (void)finish { - GRPCCall2 *call; + GRPCCall2 *copiedCall; @synchronized(self) { - call = _call; + copiedCall = _call; _call = nil; } - [call finish]; + [copiedCall finish]; } - (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { -- cgit v1.2.3 From eea5f1ad3dee4d96c9b86efe89f75c973cc57eed Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 10 Dec 2018 12:38:05 -0800 Subject: Missing nullable --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index b549f5d2bf..4ef8cee36d 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -282,7 +282,7 @@ NS_ASSUME_NONNULL_END */ @interface GRPCCall : GRXWriter -- (instancetype)init NS_UNAVAILABLE; +- (nullable instancetype)init NS_UNAVAILABLE; /** * The container of the request headers of an RPC conforms to this protocol, which is a subset of -- cgit v1.2.3 From 20c8cc72920b14520160c4e2001caec2b8acddc0 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 10 Dec 2018 18:06:34 -0800 Subject: nullability failing --- src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h b/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h index ca0cc51a52..e2c3aee3d9 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h @@ -18,6 +18,8 @@ #import "GRPCChannelPool.h" +NS_ASSUME_NONNULL_BEGIN + /** Test-only interface for \a GRPCPooledChannel. */ @interface GRPCPooledChannel (Test) @@ -31,7 +33,7 @@ /** * Return the pointer to the raw channel wrapped. */ -@property(atomic, readonly) GRPCChannel *wrappedChannel; +@property(atomic, readonly, nullable) GRPCChannel *wrappedChannel; @end @@ -45,3 +47,5 @@ - (nullable instancetype)initTestPool; @end + +NS_ASSUME_NONNULL_END -- cgit v1.2.3 From 3fc5ca0c75aae97e9201df000a5afd5f628403b8 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 12 Dec 2018 14:30:12 -0800 Subject: batch fix --- src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m | 2 +- src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m | 2 +- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m index b802137c13..8ad1e848f5 100644 --- a/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m @@ -33,7 +33,7 @@ } - (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { - grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); + grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs(args); grpc_channel *unmanagedChannel = grpc_insecure_channel_create(host.UTF8String, coreChannelArgs, NULL); GRPCFreeChannelArgs(coreChannelArgs); diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 3ccc70a744..9699889536 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -119,7 +119,7 @@ if (host.length == 0) { return NULL; } - grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs([args copy]); + grpc_channel_args *coreChannelArgs = GRPCBuildChannelArgs(args); grpc_channel *unmanagedChannel = grpc_secure_channel_create(_channelCreds, host.UTF8String, coreChannelArgs, NULL); GRPCFreeChannelArgs(coreChannelArgs); diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 4edd9d3e37..1a848a4b7c 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -307,6 +307,10 @@ - (void)channelDisconnected { @synchronized(self) { if (_call != NULL) { + // Unreference the call will lead to its cancellation in the core. Note that since + // this function is only called with a network state change, any existing GRPCCall object will + // also receive the same notification and cancel themselves with GRPCErrorCodeUnavailable, so + // the user gets GRPCErrorCodeUnavailable in this case. grpc_call_unref(_call); _call = NULL; } -- cgit v1.2.3 From 0f4d465452552cfaf16367241c8894034d1f575a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 12 Dec 2018 15:52:54 -0800 Subject: nit fix --- src/objective-c/GRPCClient/private/GRPCHost.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h index f1d5719642..ca3c52ea17 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.h +++ b/src/objective-c/GRPCClient/private/GRPCHost.h @@ -64,7 +64,7 @@ struct grpc_channel_credentials; withCertChain:(nullable NSString *)pemCertChain error:(NSError **)errorPtr; -@property(atomic, readwrite) GRPCTransportType transportType; +@property(atomic) GRPCTransportType transportType; + (GRPCCallOptions *)callOptionsForHost:(NSString *)host; -- cgit v1.2.3 From 827e84d0a4165e3e64d9ae0a1b8fbbaecdde0fa6 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 12 Dec 2018 17:21:30 -0800 Subject: Fix unused variable error --- src/objective-c/tests/Podfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index 12112f95e1..8e5f588906 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -150,7 +150,9 @@ post_install do |installer| end # Enable NSAssert on gRPC - if target.name == 'gRPC' || target.name == 'ProtoRPC' || target.name == 'RxLibrary' + if target.name == 'gRPC' || target.name.start_with?('gRPC.') || + target.name == 'ProtoRPC' || target.name.start_with?('ProtoRPC.') || + target.name == 'RxLibrary' || target.name.start_with?('RxLibrary.') target.build_configurations.each do |config| if config.name != 'Release' config.build_settings['ENABLE_NS_ASSERTIONS'] = 'YES' -- cgit v1.2.3 From 48ac4ee48a56582c86f2ada6d3281e37590c57c4 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 13 Dec 2018 11:21:45 -0800 Subject: Test assert failure --- src/objective-c/tests/InteropTests.m | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 3665e9705d..656af18888 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -197,7 +197,8 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testEmptyUnaryRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnaryWithV2API"]; + __weak XCTestExpectation *expectReceive = [self expectationWithDescription:@"EmptyUnaryWithV2API received message"]; + __weak XCTestExpectation *expectComplete = [self expectationWithDescription:@"EmptyUnaryWithV2API completed"]; GPBEmpty *request = [GPBEmpty message]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; @@ -212,11 +213,12 @@ BOOL isRemoteInteropTest(NSString *host) { if (message) { id expectedResponse = [GPBEmpty message]; XCTAssertEqualObjects(message, expectedResponse); - [expectation fulfill]; + [expectReceive fulfill]; } } closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error, @"Unexpected error: %@", error); + [expectComplete fulfill]; }] callOptions:options]; [call start]; @@ -249,9 +251,9 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testLargeUnaryRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectRecvMessage = + __weak XCTestExpectation *expectReceive = [self expectationWithDescription:@"LargeUnaryWithV2API received message"]; - __weak XCTestExpectation *expectRecvComplete = + __weak XCTestExpectation *expectComplete = [self expectationWithDescription:@"LargeUnaryWithV2API received complete"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; @@ -277,12 +279,12 @@ BOOL isRemoteInteropTest(NSString *host) { [NSMutableData dataWithLength:314159]; XCTAssertEqualObjects(message, expectedResponse); - [expectRecvMessage fulfill]; + [expectReceive fulfill]; } } closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error, @"Unexpected error: %@", error); - [expectRecvComplete fulfill]; + [expectComplete fulfill]; }] callOptions:options]; [call start]; -- cgit v1.2.3 From dc502a80988763abefb70938d020123ef0422e18 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 13 Dec 2018 11:27:26 -0800 Subject: clang-format --- src/objective-c/tests/InteropTests.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 656af18888..717dfd81f7 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -197,8 +197,10 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testEmptyUnaryRPCWithV2API { XCTAssertNotNil([[self class] host]); - __weak XCTestExpectation *expectReceive = [self expectationWithDescription:@"EmptyUnaryWithV2API received message"]; - __weak XCTestExpectation *expectComplete = [self expectationWithDescription:@"EmptyUnaryWithV2API completed"]; + __weak XCTestExpectation *expectReceive = + [self expectationWithDescription:@"EmptyUnaryWithV2API received message"]; + __weak XCTestExpectation *expectComplete = + [self expectationWithDescription:@"EmptyUnaryWithV2API completed"]; GPBEmpty *request = [GPBEmpty message]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; -- cgit v1.2.3 From b4ccbdb124e11dd740cd042cfab88aa38e34398d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 13 Dec 2018 16:48:28 -0800 Subject: Remove some annotations in GRPCRequestHeader --- src/objective-c/GRPCClient/GRPCCall.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 4ef8cee36d..f36b814cec 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -370,11 +370,11 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; -- (nullable id)objectForKeyedSubscript:(nonnull id)key; -- (void)setObject:(nullable id)obj forKeyedSubscript:(nonnull id)key; +- (id)objectForKeyedSubscript:(id)key; +- (void)setObject:(id)obj forKeyedSubscript:(id)key; - (void)removeAllObjects; -- (void)removeObjectForKey:(nonnull id)key; +- (void)removeObjectForKey:(id)key; @end #pragma clang diagnostic push -- cgit v1.2.3 From 653160d8067e648c94c7ab095dc7fe4bbe1f3271 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 14 Dec 2018 13:47:33 -0800 Subject: Make NSMutableDictionary annotation right --- src/objective-c/GRPCClient/GRPCCall.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index f36b814cec..d4d16024fa 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -370,11 +370,11 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; -- (id)objectForKeyedSubscript:(id)key; -- (void)setObject:(id)obj forKeyedSubscript:(id)key; +- (nullable id)objectForKeyedSubscript:(nonnull id)key; +- (void)setObject:(nonnull id)obj forKeyedSubscript:(nonnull id)key; - (void)removeAllObjects; -- (void)removeObjectForKey:(id)key; +- (void)removeObjectForKey:(nonnull id)key; @end #pragma clang diagnostic push -- cgit v1.2.3 From 4f91630d6b2ba9fbf0b75e2dbaa1932a739f2b17 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 14 Dec 2018 13:46:53 -0800 Subject: CFStream use serial dispatch queue --- src/core/lib/iomgr/cfstream_handle.cc | 98 ++++++++++++++++------------------- src/core/lib/iomgr/cfstream_handle.h | 2 + 2 files changed, 46 insertions(+), 54 deletions(-) diff --git a/src/core/lib/iomgr/cfstream_handle.cc b/src/core/lib/iomgr/cfstream_handle.cc index 827fd24831..bb402f96cf 100644 --- a/src/core/lib/iomgr/cfstream_handle.cc +++ b/src/core/lib/iomgr/cfstream_handle.cc @@ -52,62 +52,53 @@ CFStreamHandle* CFStreamHandle::CreateStreamHandle( void CFStreamHandle::ReadCallback(CFReadStreamRef stream, CFStreamEventType type, void* client_callback_info) { + grpc_core::ExecCtx exec_ctx; CFStreamHandle* handle = static_cast(client_callback_info); - CFSTREAM_HANDLE_REF(handle, "read callback"); - dispatch_async( - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - grpc_core::ExecCtx exec_ctx; - if (grpc_tcp_trace.enabled()) { - gpr_log(GPR_DEBUG, "CFStream ReadCallback (%p, %p, %lu, %p)", handle, - stream, type, client_callback_info); - } - switch (type) { - case kCFStreamEventOpenCompleted: - handle->open_event_.SetReady(); - break; - case kCFStreamEventHasBytesAvailable: - case kCFStreamEventEndEncountered: - handle->read_event_.SetReady(); - break; - case kCFStreamEventErrorOccurred: - handle->open_event_.SetReady(); - handle->read_event_.SetReady(); - break; - default: - GPR_UNREACHABLE_CODE(return ); - } - CFSTREAM_HANDLE_UNREF(handle, "read callback"); - }); + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_DEBUG, "CFStream ReadCallback (%p, %p, %lu, %p)", handle, + stream, type, client_callback_info); + } + switch (type) { + case kCFStreamEventOpenCompleted: + handle->open_event_.SetReady(); + break; + case kCFStreamEventHasBytesAvailable: + case kCFStreamEventEndEncountered: + handle->read_event_.SetReady(); + break; + case kCFStreamEventErrorOccurred: + handle->open_event_.SetReady(); + handle->read_event_.SetReady(); + break; + default: + GPR_UNREACHABLE_CODE(return ); + } } void CFStreamHandle::WriteCallback(CFWriteStreamRef stream, CFStreamEventType type, void* clientCallBackInfo) { + grpc_core::ExecCtx exec_ctx; CFStreamHandle* handle = static_cast(clientCallBackInfo); - CFSTREAM_HANDLE_REF(handle, "write callback"); - dispatch_async( - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - grpc_core::ExecCtx exec_ctx; - if (grpc_tcp_trace.enabled()) { - gpr_log(GPR_DEBUG, "CFStream WriteCallback (%p, %p, %lu, %p)", handle, - stream, type, clientCallBackInfo); - } - switch (type) { - case kCFStreamEventOpenCompleted: - handle->open_event_.SetReady(); - break; - case kCFStreamEventCanAcceptBytes: - case kCFStreamEventEndEncountered: - handle->write_event_.SetReady(); - break; - case kCFStreamEventErrorOccurred: - handle->open_event_.SetReady(); - handle->write_event_.SetReady(); - break; - default: - GPR_UNREACHABLE_CODE(return ); - } - CFSTREAM_HANDLE_UNREF(handle, "write callback"); - }); + printf("** CFStreamHandle::WriteCallback\n"); + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_DEBUG, "CFStream WriteCallback (%p, %p, %lu, %p)", handle, + stream, type, clientCallBackInfo); + } + switch (type) { + case kCFStreamEventOpenCompleted: + handle->open_event_.SetReady(); + break; + case kCFStreamEventCanAcceptBytes: + case kCFStreamEventEndEncountered: + handle->write_event_.SetReady(); + break; + case kCFStreamEventErrorOccurred: + handle->open_event_.SetReady(); + handle->write_event_.SetReady(); + break; + default: + GPR_UNREACHABLE_CODE(return ); + } } CFStreamHandle::CFStreamHandle(CFReadStreamRef read_stream, @@ -116,6 +107,7 @@ CFStreamHandle::CFStreamHandle(CFReadStreamRef read_stream, open_event_.InitEvent(); read_event_.InitEvent(); write_event_.InitEvent(); + dispatch_queue_ = dispatch_queue_create(nullptr, DISPATCH_QUEUE_SERIAL); CFStreamClientContext ctx = {0, static_cast(this), CFStreamHandle::Retain, CFStreamHandle::Release, nil}; @@ -129,10 +121,8 @@ CFStreamHandle::CFStreamHandle(CFReadStreamRef read_stream, kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, CFStreamHandle::WriteCallback, &ctx); - CFReadStreamScheduleWithRunLoop(read_stream, CFRunLoopGetMain(), - kCFRunLoopCommonModes); - CFWriteStreamScheduleWithRunLoop(write_stream, CFRunLoopGetMain(), - kCFRunLoopCommonModes); + CFReadStreamSetDispatchQueue(read_stream, dispatch_queue_); + CFWriteStreamSetDispatchQueue(write_stream, dispatch_queue_); } CFStreamHandle::~CFStreamHandle() { diff --git a/src/core/lib/iomgr/cfstream_handle.h b/src/core/lib/iomgr/cfstream_handle.h index 4258e72431..93ec5f044b 100644 --- a/src/core/lib/iomgr/cfstream_handle.h +++ b/src/core/lib/iomgr/cfstream_handle.h @@ -62,6 +62,8 @@ class CFStreamHandle final { grpc_core::LockfreeEvent read_event_; grpc_core::LockfreeEvent write_event_; + dispatch_queue_t dispatch_queue_; + gpr_refcount refcount_; }; -- cgit v1.2.3 From 4196f59a445a53246f3835b52b49613c9ebd091e Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 14 Dec 2018 16:06:15 -0800 Subject: more nullability annotation --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- src/objective-c/GRPCClient/GRPCCallOptions.h | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index d4d16024fa..404d4b7656 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -282,7 +282,7 @@ NS_ASSUME_NONNULL_END */ @interface GRPCCall : GRXWriter -- (nullable instancetype)init NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; /** * The container of the request headers of an RPC conforms to this protocol, which is a subset of diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index b7f08480dc..b866f268ee 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -18,6 +18,8 @@ #import +NS_ASSUME_NONNULL_BEGIN + /** * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1 */ @@ -66,7 +68,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ -- (void)provideTokenToHandler:(void (^_Nullable)(NSString *_Nullable token))handler; +- (void)provideTokenToHandler:(void (^)(NSString *_Nullable token))handler; /** * This method is deprecated. Please use \a provideTokenToHandler. @@ -74,7 +76,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ -- (void)getTokenWithHandler:(void (^_Nullable)(NSString *_Nullable token))handler; +- (void)getTokenWithHandler:(void (^)(NSString *_Nullable token))handler; @end @@ -210,7 +212,7 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * Return if the channel options are equal to another object. */ -- (BOOL)hasChannelOptionsEqualTo:(nonnull GRPCCallOptions *)callOptions; +- (BOOL)hasChannelOptionsEqualTo:(GRPCCallOptions *)callOptions; /** * Hash for channel options. @@ -352,3 +354,5 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { @property(readwrite) NSUInteger channelID; @end + +NS_ASSUME_NONNULL_END -- cgit v1.2.3 From b90652ab0329e67697e71282b785187a4d1cb223 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 14 Dec 2018 16:07:20 -0800 Subject: remove debug information --- src/core/lib/iomgr/cfstream_handle.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/lib/iomgr/cfstream_handle.cc b/src/core/lib/iomgr/cfstream_handle.cc index bb402f96cf..6cb9ca1a0d 100644 --- a/src/core/lib/iomgr/cfstream_handle.cc +++ b/src/core/lib/iomgr/cfstream_handle.cc @@ -79,7 +79,6 @@ void CFStreamHandle::WriteCallback(CFWriteStreamRef stream, void* clientCallBackInfo) { grpc_core::ExecCtx exec_ctx; CFStreamHandle* handle = static_cast(clientCallBackInfo); - printf("** CFStreamHandle::WriteCallback\n"); if (grpc_tcp_trace.enabled()) { gpr_log(GPR_DEBUG, "CFStream WriteCallback (%p, %p, %lu, %p)", handle, stream, type, clientCallBackInfo); -- cgit v1.2.3 From c097e21259db28d8b80ed661c0c0e3d808466ed1 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 14 Dec 2018 17:55:11 -0800 Subject: Nullability annotation fix --- src/objective-c/GRPCClient/GRPCCall.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 404d4b7656..15b1c90449 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -282,7 +282,7 @@ NS_ASSUME_NONNULL_END */ @interface GRPCCall : GRXWriter -- (instancetype)init NS_UNAVAILABLE; +- (nonnull instancetype)init NS_UNAVAILABLE; /** * The container of the request headers of an RPC conforms to this protocol, which is a subset of -- cgit v1.2.3 From 915cd71b4a6aceb8003077e0e360ea7accbde38c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 17 Dec 2018 17:36:28 -0800 Subject: nullability revert --- src/objective-c/GRPCClient/GRPCCall.h | 32 +++++++++++++++++--------------- src/objective-c/ProtoRPC/ProtoRPC.h | 9 ++++----- src/objective-c/ProtoRPC/ProtoService.h | 33 +++++++++++++++++---------------- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 15b1c90449..6669067fbf 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -275,6 +275,9 @@ extern NSString *const kGRPCTrailersKey; NS_ASSUME_NONNULL_END +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + /** * This interface is deprecated. Please use \a GRPCcall2. * @@ -282,7 +285,7 @@ NS_ASSUME_NONNULL_END */ @interface GRPCCall : GRXWriter -- (nonnull instancetype)init NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; /** * The container of the request headers of an RPC conforms to this protocol, which is a subset of @@ -308,7 +311,7 @@ NS_ASSUME_NONNULL_END * * The property is initialized to an empty NSMutableDictionary. */ -@property(nonnull, atomic, readonly) NSMutableDictionary *requestHeaders; +@property(atomic, readonly) NSMutableDictionary *requestHeaders; /** * This dictionary is populated with the HTTP headers received from the server. This happens before @@ -319,7 +322,7 @@ NS_ASSUME_NONNULL_END * The value of this property is nil until all response headers are received, and will change before * any of -writeValue: or -writesFinishedWithError: are sent to the writeable. */ -@property(nullable, atomic, readonly) NSDictionary *responseHeaders; +@property(atomic, readonly) NSDictionary *responseHeaders; /** * Same as responseHeaders, but populated with the HTTP trailers received from the server before the @@ -328,7 +331,7 @@ NS_ASSUME_NONNULL_END * The value of this property is nil until all response trailers are received, and will change * before -writesFinishedWithError: is sent to the writeable. */ -@property(nullable, atomic, readonly) NSDictionary *responseTrailers; +@property(atomic, readonly) NSDictionary *responseTrailers; /** * The request writer has to write NSData objects into the provided Writeable. The server will @@ -341,9 +344,9 @@ NS_ASSUME_NONNULL_END * host parameter should not contain the scheme (http:// or https://), only the name or IP addr * and the port number, for example @"localhost:5050". */ -- (nullable instancetype)initWithHost:(nonnull NSString *)host - path:(nonnull NSString *)path - requestsWriter:(nonnull GRXWriter *)requestWriter; +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + requestsWriter:(GRXWriter *)requestWriter; /** * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and @@ -354,12 +357,10 @@ NS_ASSUME_NONNULL_END /** * The following methods are deprecated. */ -+ (void)setCallSafety:(GRPCCallSafety)callSafety - host:(nonnull NSString *)host - path:(nonnull NSString *)path; -@property(nullable, atomic, copy, readwrite) NSString *serverName; ++ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; +@property(atomic, copy, readwrite) NSString *serverName; @property NSTimeInterval timeout; -- (void)setResponseDispatchQueue:(nonnull dispatch_queue_t)queue; +- (void)setResponseDispatchQueue:(dispatch_queue_t)queue; @end @@ -370,11 +371,11 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @protocol GRPCRequestHeaders @property(nonatomic, readonly) NSUInteger count; -- (nullable id)objectForKeyedSubscript:(nonnull id)key; -- (void)setObject:(nonnull id)obj forKeyedSubscript:(nonnull id)key; +- (id)objectForKeyedSubscript:(id)key; +- (void)setObject:(id)obj forKeyedSubscript:(id)key; - (void)removeAllObjects; -- (void)removeObjectForKey:(nonnull id)key; +- (void)removeObjectForKey:(id)key; @end #pragma clang diagnostic push @@ -383,3 +384,4 @@ DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") @interface NSMutableDictionary (GRPCRequestHeaders) @end #pragma clang diagnostic pop +#pragma clang diagnostic pop diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index e6ba1f66ca..91a50d395a 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -142,11 +142,10 @@ __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC * addr and the port number, for example @"localhost:5050". */ - - (nullable instancetype)initWithHost : (nonnull NSString *)host method - : (nonnull GRPCProtoMethod *)method requestsWriter - : (nonnull GRXWriter *)requestsWriter responseClass - : (nonnull Class)responseClass responsesWriteable - : (nonnull id)responsesWriteable NS_DESIGNATED_INITIALIZER; + (instancetype)initWithHost : (NSString *)host method + : (GRPCProtoMethod *)method requestsWriter : (GRXWriter *)requestsWriter responseClass + : (Class)responseClass responsesWriteable + : (id)responsesWriteable NS_DESIGNATED_INITIALIZER; - (void)start; @end diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index 70423ee9de..d76e96ce2a 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -27,38 +27,41 @@ @class GRPCStreamingProtoCall; @protocol GRPCProtoResponseCallbacks; -NS_ASSUME_NONNULL_BEGIN +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoService : NSObject - - (nullable instancetype)initWithHost : (NSString *)host packageName - : (NSString *)packageName serviceName : (NSString *)serviceName callOptions + (nullable instancetype)initWithHost : (nonnull NSString *)host packageName + : (nonnull NSString *)packageName serviceName : (nonnull NSString *)serviceName callOptions : (nullable GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; - (instancetype)initWithHost:(NSString *)host packageName:(NSString *)packageName serviceName:(NSString *)serviceName; -- (nullable GRPCProtoCall *)RPCToMethod:(NSString *)method - requestsWriter:(GRXWriter *)requestsWriter - responseClass:(Class)responseClass - responsesWriteable:(id)responsesWriteable; +- (GRPCProtoCall *)RPCToMethod:(NSString *)method + requestsWriter:(GRXWriter *)requestsWriter + responseClass:(Class)responseClass + responsesWriteable:(id)responsesWriteable; -- (nullable GRPCUnaryProtoCall *)RPCToMethod:(NSString *)method - message:(id)message - responseHandler:(id)handler +- (nullable GRPCUnaryProtoCall *)RPCToMethod:(nonnull NSString *)method + message:(nonnull id)message + responseHandler:(nonnull id)handler callOptions:(nullable GRPCCallOptions *)callOptions - responseClass:(Class)responseClass; + responseClass:(nonnull Class)responseClass; -- (nullable GRPCStreamingProtoCall *)RPCToMethod:(NSString *)method - responseHandler:(id)handler +- (nullable GRPCStreamingProtoCall *)RPCToMethod:(nonnull NSString *)method + responseHandler:(nonnull id)handler callOptions:(nullable GRPCCallOptions *)callOptions - responseClass:(Class)responseClass; + responseClass:(nonnull Class)responseClass; @end +#pragma clang diagnostic pop + /** * This subclass is empty now. Eventually we'll remove ProtoService class * to avoid potential naming conflict @@ -69,5 +72,3 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoServ #pragma clang diagnostic pop @end - - NS_ASSUME_NONNULL_END -- cgit v1.2.3 From 8c3df503ad59a6c66e1b1ab6257b52c508ec37dc Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 17 Dec 2018 21:54:53 -0800 Subject: Fix compatibility test failures --- src/objective-c/GRPCClient/GRPCCall.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index cfd0de1a8a..39e4967ec9 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -484,8 +484,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; callSafety:(GRPCCallSafety)safety requestsWriter:(GRXWriter *)requestWriter callOptions:(GRPCCallOptions *)callOptions { - // Purposely using pointer rather than length ([host length] == 0) for backwards compatibility. - NSAssert(host.length != 0 && path.length != 0, @"Neither host nor path can be nil."); + // Purposely using pointer rather than length (host.length == 0) for backwards compatibility. + NSAssert(host != nil && path != nil, @"Neither host nor path can be nil."); NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); NSAssert(requestWriter.state == GRXWriterStateNotStarted, @"The requests writer can't be already started."); -- cgit v1.2.3 From d36a13af3182495079bee65ff78e3e7e7f0d5901 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 17 Dec 2018 21:55:26 -0800 Subject: Try use alternative simulator for APIv2Tests --- src/objective-c/tests/run_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index e8c3e6ec2a..f075d9baad 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -187,7 +187,7 @@ echo "TIME: $(date)" xcodebuild \ -workspace Tests.xcworkspace \ -scheme APIv2Tests \ - -destination name="iPhone 8" \ + -destination name="iPhone X" \ test \ | egrep -v "$XCODEBUILD_FILTER" \ | egrep -v '^$' \ -- cgit v1.2.3 From 8bc8ff3dce507f912b8985fefaa22da1e2d95b6d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 18 Dec 2018 11:13:13 -0800 Subject: Fix nullability incompatibility --- src/compiler/objective_c_generator.cc | 11 +++++------ src/objective-c/ProtoRPC/ProtoRPC.h | 5 +++++ src/objective-c/ProtoRPC/ProtoService.m | 10 +++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc index 0a6b64f595..af5398ec68 100644 --- a/src/compiler/objective_c_generator.cc +++ b/src/compiler/objective_c_generator.cc @@ -355,7 +355,7 @@ void PrintMethodImplementations(Printer* printer, "@implementation $service_class$\n\n" "// Designated initializer\n" "- (instancetype)initWithHost:(NSString *)host " - "callOptions:(GRPCCallOptions *_Nullable)callOptions{\n" + "callOptions:(GRPCCallOptions *_Nullable)callOptions {\n" " self = [super initWithHost:host\n" " packageName:@\"$package$\"\n" " serviceName:@\"$service_name$\"\n" @@ -363,10 +363,9 @@ void PrintMethodImplementations(Printer* printer, " return self;\n" "}\n\n" "- (instancetype)initWithHost:(NSString *)host {\n" - " return [self initWithHost:host\n" - " packageName:@\"$package$\"\n" - " serviceName:@\"$service_name$\"\n" - " callOptions:nil];\n" + " return [super initWithHost:host\n" + " packageName:@\"$package$\"\n" + " serviceName:@\"$service_name$\"];\n" "}\n\n"); printer.Print( @@ -381,7 +380,7 @@ void PrintMethodImplementations(Printer* printer, printer.Print( "#pragma mark - Class Methods\n\n" "+ (instancetype)serviceWithHost:(NSString *)host {\n" - " return [self serviceWithHost:host callOptions:nil];\n" + " return [[self alloc] initWithHost:host];\n" "}\n\n" "+ (instancetype)serviceWithHost:(NSString *)host " "callOptions:(GRPCCallOptions *_Nullable)callOptions {\n" diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index 91a50d395a..8ce3421cc1 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -134,6 +134,9 @@ NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC : GRPCCall @@ -160,3 +163,5 @@ __attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC #pragma clang diagnostic pop @end + +#pragma clang diagnostic pop diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m index 3d998bfaeb..b7c7fadbcf 100644 --- a/src/objective-c/ProtoRPC/ProtoService.m +++ b/src/objective-c/ProtoRPC/ProtoService.m @@ -61,7 +61,15 @@ - (instancetype)initWithHost:(NSString *)host packageName:(NSString *)packageName serviceName:(NSString *)serviceName { - return [self initWithHost:host packageName:packageName serviceName:serviceName callOptions:nil]; + // Do not call designated initializer here due to nullability incompatibility. This method is from + // old API and does not assert on nullability of the parameters. + if ((self = [super init])) { + _host = [host copy]; + _packageName = [packageName copy]; + _serviceName = [serviceName copy]; + _callOptions = nil; + } + return self; } - (GRPCProtoCall *)RPCToMethod:(NSString *)method -- cgit v1.2.3 From d79b3fe3207f7bd064d584c6e15517680749e2d5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 18 Dec 2018 14:28:36 -0800 Subject: Fix test --- src/objective-c/tests/GRPCClientTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index b16720557f..3ef046835e 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -365,7 +365,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; GRXWriter *writer = [GRXWriter writerWithValue:[NSData data]]; // Try to set parameters to nil for GRPCCall. This should cause an exception @try { - (void)[[GRPCCall alloc] initWithHost:@"" path:@"" requestsWriter:writer]; + (void)[[GRPCCall alloc] initWithHost:nil path:nil requestsWriter:writer]; XCTFail(@"Did not receive an exception when parameters are nil"); } @catch (NSException *theException) { NSLog(@"Received exception as expected: %@", theException.name); -- cgit v1.2.3 From 3f57e3451bf4a3687e70e92fc218ea25ff7a17c9 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 08:09:12 -0800 Subject: Try earlier APIv2Tests --- src/objective-c/tests/run_tests.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index f075d9baad..aab80ded61 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -176,7 +176,7 @@ xcodebuild \ echo "TIME: $(date)" xcodebuild \ -workspace Tests.xcworkspace \ - -scheme ChannelTests \ + -scheme APIv2Tests \ -destination name="iPhone 8" \ test \ | egrep -v "$XCODEBUILD_FILTER" \ @@ -186,11 +186,12 @@ xcodebuild \ echo "TIME: $(date)" xcodebuild \ -workspace Tests.xcworkspace \ - -scheme APIv2Tests \ - -destination name="iPhone X" \ + -scheme ChannelTests \ + -destination name="iPhone 8" \ test \ | egrep -v "$XCODEBUILD_FILTER" \ | egrep -v '^$' \ | egrep -v "(GPBDictionary|GPBArray)" - + exit 0 -- cgit v1.2.3 From 25e73664136ea01e2b8a64149a97e782c57d9f7d Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 09:16:26 -0800 Subject: Revert "Rename getTokenWithHandler" Since the renamed protocol is breaking people and is not general enough, we revert the rename and leave the work to interceptor This reverts commit 92db5fc72488f9d62b81ee311a79832df787f3ef. --- src/objective-c/GRPCClient/GRPCCall.m | 14 ++------------ src/objective-c/GRPCClient/GRPCCallOptions.h | 12 +----------- src/objective-c/ProtoRPC/ProtoRPC.m | 2 +- src/objective-c/tests/APIv2Tests/APIv2Tests.m | 2 +- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 39e4967ec9..9bcacac0df 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -885,7 +885,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; @synchronized(self) { self.isWaitingForToken = YES; } - void (^tokenHandler)(NSString *token) = ^(NSString *token) { + [_callOptions.authTokenProvider getTokenWithHandler:^(NSString *token) { @synchronized(self) { if (self.isWaitingForToken) { if (token) { @@ -895,17 +895,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; self.isWaitingForToken = NO; } } - }; - id authTokenProvider = _callOptions.authTokenProvider; - if ([authTokenProvider respondsToSelector:@selector(provideTokenToHandler:)]) { - [_callOptions.authTokenProvider provideTokenToHandler:tokenHandler]; - } else { - NSAssert([authTokenProvider respondsToSelector:@selector(getTokenWithHandler:)], - @"authTokenProvider has no usable method"); - if ([authTokenProvider respondsToSelector:@selector(getTokenWithHandler:)]) { - [_callOptions.authTokenProvider getTokenWithHandler:tokenHandler]; - } - } + }]; } else { [self startCallWithWriteable:writeable]; } diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index b866f268ee..b5bf4c9eb6 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -60,22 +60,12 @@ typedef NS_ENUM(NSUInteger, GRPCTransportType) { /** * Implement this protocol to provide a token to gRPC when a call is initiated. */ -@protocol GRPCAuthorizationProtocol - -@optional +@protocol GRPCAuthorizationProtocol /** * This method is called when gRPC is about to start the call. When OAuth token is acquired, * \a handler is expected to be called with \a token being the new token to be used for this call. */ -- (void)provideTokenToHandler:(void (^)(NSString *_Nullable token))handler; - -/** - * This method is deprecated. Please use \a provideTokenToHandler. - * - * This method is called when gRPC is about to start the call. When OAuth token is acquired, - * \a handler is expected to be called with \a token being the new token to be used for this call. - */ - (void)getTokenWithHandler:(void (^)(NSString *_Nullable token))handler; @end diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index abf224c3cf..48a38bd35a 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -175,7 +175,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)writeMessage:(GPBMessage *)message { - NSAssert([message isKindOfClass:[GPBMessage class]], @"Parameter message must be a GPBMessage"); + NSAssert([message isKindOfClass:[GPBMessage class]]); if (![message isKindOfClass:[GPBMessage class]]) { NSLog(@"Failed to send a message that is non-proto."); return; diff --git a/src/objective-c/tests/APIv2Tests/APIv2Tests.m b/src/objective-c/tests/APIv2Tests/APIv2Tests.m index fd472aafeb..ca7bf47283 100644 --- a/src/objective-c/tests/APIv2Tests/APIv2Tests.m +++ b/src/objective-c/tests/APIv2Tests/APIv2Tests.m @@ -241,7 +241,7 @@ static const NSTimeInterval kTestTimeout = 16; [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; } -- (void)provideTokenToHandler:(void (^)(NSString *token))handler { +- (void)getTokenWithHandler:(void (^)(NSString *token))handler { dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); dispatch_sync(queue, ^{ handler(@"test-access-token"); -- cgit v1.2.3 From 72dc62ee2e20919b98939ee2e6337fd63a988f48 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 10:30:54 -0800 Subject: Revert "Try earlier APIv2Tests" This reverts commit 3f57e3451bf4a3687e70e92fc218ea25ff7a17c9. --- src/objective-c/tests/run_tests.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index aab80ded61..f075d9baad 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -176,7 +176,7 @@ xcodebuild \ echo "TIME: $(date)" xcodebuild \ -workspace Tests.xcworkspace \ - -scheme APIv2Tests \ + -scheme ChannelTests \ -destination name="iPhone 8" \ test \ | egrep -v "$XCODEBUILD_FILTER" \ @@ -186,12 +186,11 @@ xcodebuild \ echo "TIME: $(date)" xcodebuild \ -workspace Tests.xcworkspace \ - -scheme ChannelTests \ - -destination name="iPhone 8" \ + -scheme APIv2Tests \ + -destination name="iPhone X" \ test \ | egrep -v "$XCODEBUILD_FILTER" \ | egrep -v '^$' \ | egrep -v "(GPBDictionary|GPBArray)" - - exit 0 -- cgit v1.2.3 From 92123a4a333719fa3aa55b3db9f36c136e108a47 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 10:42:31 -0800 Subject: Rebuild APIv2Tests --- .../tests/Tests.xcodeproj/project.pbxproj | 398 +++++++++++---------- .../xcshareddata/xcschemes/APIv2Tests.xcscheme | 8 +- src/objective-c/tests/run_tests.sh | 2 +- 3 files changed, 208 insertions(+), 200 deletions(-) diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index 6f24d3512f..47b79a0534 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -16,7 +16,7 @@ 333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; }; 5E0282E9215AA697007AC99D /* UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* UnitTests.m */; }; 5E0282EB215AA697007AC99D /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; - 5E10F5AA218CB0D2008BAB68 /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E10F5A9218CB0D2008BAB68 /* APIv2Tests.m */; }; + 5E3B95A521CAC6C500C0A151 /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3B95A421CAC6C500C0A151 /* APIv2Tests.m */; }; 5E7D71AD210954A8001EA6BA /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; 5E7D71B5210B9EC9001EA6BA /* InteropTestsCallOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */; }; 5E7D71B7210B9EC9001EA6BA /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; }; @@ -66,10 +66,10 @@ 6C1A3F81CCF7C998B4813EFD /* libPods-InteropTestsCallOptions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF3FC2CFFE7B0961823BC740 /* libPods-InteropTestsCallOptions.a */; }; 886717A79EFF774F356798E6 /* libPods-InteropTestsMultipleChannels.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 355D0E30AD224763BC9519F4 /* libPods-InteropTestsMultipleChannels.a */; }; 91D4B3C85B6D8562F409CB48 /* libPods-InteropTestsLocalSSLCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */; }; + 98478C9F42329DF769A45B6C /* libPods-APIv2Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B6AD69CACF67505B0F028E92 /* libPods-APIv2Tests.a */; }; BC111C80CBF7068B62869352 /* libPods-InteropTestsRemoteCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */; }; C3D6F4270A2FFF634D8849ED /* libPods-InteropTestsLocalCleartextCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */; }; CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */; }; - E7F4C80FC8FC667B7447BFE7 /* libPods-APIv2Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B6AD69CACF67505B0F028E92 /* libPods-APIv2Tests.a */; }; F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */; }; /* End PBXBuildFile section */ @@ -212,9 +212,9 @@ 5E0282E6215AA697007AC99D /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5E0282E8215AA697007AC99D /* UnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnitTests.m; sourceTree = ""; }; 5E0282EA215AA697007AC99D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 5E10F5A7218CB0D1008BAB68 /* APIv2Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APIv2Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 5E10F5A9218CB0D2008BAB68 /* APIv2Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = APIv2Tests.m; sourceTree = ""; }; - 5E10F5AB218CB0D2008BAB68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5E3B95A221CAC6C500C0A151 /* APIv2Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APIv2Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E3B95A421CAC6C500C0A151 /* APIv2Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = APIv2Tests.m; sourceTree = ""; }; + 5E3B95A621CAC6C500C0A151 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsCallOptions.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5E7D71B4210B9EC9001EA6BA /* InteropTestsCallOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsCallOptions.m; sourceTree = ""; }; 5E7D71B6210B9EC9001EA6BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -313,11 +313,11 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5E10F5A4218CB0D1008BAB68 /* Frameworks */ = { + 5E3B959F21CAC6C500C0A151 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E7F4C80FC8FC667B7447BFE7 /* libPods-APIv2Tests.a in Frameworks */, + 98478C9F42329DF769A45B6C /* libPods-APIv2Tests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -561,11 +561,11 @@ path = UnitTests; sourceTree = ""; }; - 5E10F5A8218CB0D1008BAB68 /* APIv2Tests */ = { + 5E3B95A321CAC6C500C0A151 /* APIv2Tests */ = { isa = PBXGroup; children = ( - 5E10F5A9218CB0D2008BAB68 /* APIv2Tests.m */, - 5E10F5AB218CB0D2008BAB68 /* Info.plist */, + 5E3B95A421CAC6C500C0A151 /* APIv2Tests.m */, + 5E3B95A621CAC6C500C0A151 /* Info.plist */, ); path = APIv2Tests; sourceTree = ""; @@ -636,7 +636,7 @@ 5EB2A2F62109284500EB4B69 /* InteropTestsMultipleChannels */, 5E7D71B3210B9EC9001EA6BA /* InteropTestsCallOptions */, 5E0282E7215AA697007AC99D /* UnitTests */, - 5E10F5A8218CB0D1008BAB68 /* APIv2Tests */, + 5E3B95A321CAC6C500C0A151 /* APIv2Tests */, 635697C81B14FC11007A7283 /* Products */, 51E4650F34F854F41FF053B3 /* Pods */, 136D535E19727099B941D7B1 /* Frameworks */, @@ -662,7 +662,7 @@ 5EB2A2F52109284500EB4B69 /* InteropTestsMultipleChannels.xctest */, 5E7D71B2210B9EC8001EA6BA /* InteropTestsCallOptions.xctest */, 5E0282E6215AA697007AC99D /* UnitTests.xctest */, - 5E10F5A7218CB0D1008BAB68 /* APIv2Tests.xctest */, + 5E3B95A221CAC6C500C0A151 /* APIv2Tests.xctest */, ); name = Products; sourceTree = ""; @@ -715,15 +715,15 @@ productReference = 5E0282E6215AA697007AC99D /* UnitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 5E10F5A6218CB0D1008BAB68 /* APIv2Tests */ = { + 5E3B95A121CAC6C500C0A151 /* APIv2Tests */ = { isa = PBXNativeTarget; - buildConfigurationList = 5E10F5B0218CB0D2008BAB68 /* Build configuration list for PBXNativeTarget "APIv2Tests" */; + buildConfigurationList = 5E3B95A721CAC6C500C0A151 /* Build configuration list for PBXNativeTarget "APIv2Tests" */; buildPhases = ( - 031ADD72298D6C6979CB06DB /* [CP] Check Pods Manifest.lock */, - 5E10F5A3218CB0D1008BAB68 /* Sources */, - 5E10F5A4218CB0D1008BAB68 /* Frameworks */, - 5E10F5A5218CB0D1008BAB68 /* Resources */, - FBB92A8B11C52512E67791E8 /* [CP] Copy Pods Resources */, + EDDD3FA856BCA3443ED36D1E /* [CP] Check Pods Manifest.lock */, + 5E3B959E21CAC6C500C0A151 /* Sources */, + 5E3B959F21CAC6C500C0A151 /* Frameworks */, + 5E3B95A021CAC6C500C0A151 /* Resources */, + C17B826BBD02FDD4A5F355AF /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -731,7 +731,7 @@ ); name = APIv2Tests; productName = APIv2Tests; - productReference = 5E10F5A7218CB0D1008BAB68 /* APIv2Tests.xctest */; + productReference = 5E3B95A221CAC6C500C0A151 /* APIv2Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */ = { @@ -1043,7 +1043,7 @@ CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; }; - 5E10F5A6218CB0D1008BAB68 = { + 5E3B95A121CAC6C500C0A151 = { CreatedOnToolsVersion = 10.0; ProvisioningStyle = Automatic; }; @@ -1128,7 +1128,7 @@ 5EB2A2F42109284500EB4B69 /* InteropTestsMultipleChannels */, 5E7D71B1210B9EC8001EA6BA /* InteropTestsCallOptions */, 5E0282E5215AA697007AC99D /* UnitTests */, - 5E10F5A6218CB0D1008BAB68 /* APIv2Tests */, + 5E3B95A121CAC6C500C0A151 /* APIv2Tests */, ); }; /* End PBXProject section */ @@ -1141,7 +1141,7 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5E10F5A5218CB0D1008BAB68 /* Resources */ = { + 5E3B95A021CAC6C500C0A151 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -1271,24 +1271,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 031ADD72298D6C6979CB06DB /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-APIv2Tests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; 0617B5294978A95BEBBFF733 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1721,6 +1703,28 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + C17B826BBD02FDD4A5F355AF /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; C2E09DC4BD239F71160F0CC1 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1793,25 +1797,29 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - F07941C0BAF6A7C67AA60C48 /* [CP] Check Pods Manifest.lock */ = { + EDDD3FA856BCA3443ED36D1E /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-UnitTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-APIv2Tests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - F3D5B2CDA172580341682830 /* [CP] Check Pods Manifest.lock */ = { + F07941C0BAF6A7C67AA60C48 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1822,14 +1830,14 @@ ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-InteropTestsLocalSSLCFStream-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-UnitTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - F58F17E425446B15028B9F74 /* [CP] Check Pods Manifest.lock */ = { + F3D5B2CDA172580341682830 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1840,29 +1848,29 @@ ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-CoreCronetEnd2EndTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-InteropTestsLocalSSLCFStream-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - FBB92A8B11C52512E67791E8 /* [CP] Copy Pods Resources */ = { + F58F17E425446B15028B9F74 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Copy Pods Resources"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", + "$(DERIVED_FILE_DIR)/Pods-CoreCronetEnd2EndTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-APIv2Tests/Pods-APIv2Tests-resources.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -1876,11 +1884,11 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5E10F5A3218CB0D1008BAB68 /* Sources */ = { + 5E3B959E21CAC6C500C0A151 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5E10F5AA218CB0D2008BAB68 /* APIv2Tests.m in Sources */, + 5E3B95A521CAC6C500C0A151 /* APIv2Tests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2207,141 +2215,6 @@ }; name = Release; }; - 5E10F5AC218CB0D2008BAB68 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 1286B30AD74CB64CD91FB17D /* Pods-APIv2Tests.debug.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 5E10F5AD218CB0D2008BAB68 /* Test */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 51F2A64B7AADBA1B225B132E /* Pods-APIv2Tests.test.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Test; - }; - 5E10F5AE218CB0D2008BAB68 /* Cronet */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8C233E85C3EB45B3CAE52EDF /* Pods-APIv2Tests.cronet.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Cronet; - }; - 5E10F5AF218CB0D2008BAB68 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 12B238CD1702393C2BA5DE80 /* Pods-APIv2Tests.release.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; 5E1228981E4D400F00E8504F /* Test */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2550,6 +2423,141 @@ }; name = Test; }; + 5E3B95A821CAC6C500C0A151 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1286B30AD74CB64CD91FB17D /* Pods-APIv2Tests.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5E3B95A921CAC6C500C0A151 /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 51F2A64B7AADBA1B225B132E /* Pods-APIv2Tests.test.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Test; + }; + 5E3B95AA21CAC6C500C0A151 /* Cronet */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8C233E85C3EB45B3CAE52EDF /* Pods-APIv2Tests.cronet.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Cronet; + }; + 5E3B95AB21CAC6C500C0A151 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 12B238CD1702393C2BA5DE80 /* Pods-APIv2Tests.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = APIv2Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 5E7D71BB210B9EC9001EA6BA /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 3A98DF08852F60AF1D96481D /* Pods-InteropTestsCallOptions.debug.xcconfig */; @@ -3892,13 +3900,13 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 5E10F5B0218CB0D2008BAB68 /* Build configuration list for PBXNativeTarget "APIv2Tests" */ = { + 5E3B95A721CAC6C500C0A151 /* Build configuration list for PBXNativeTarget "APIv2Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 5E10F5AC218CB0D2008BAB68 /* Debug */, - 5E10F5AD218CB0D2008BAB68 /* Test */, - 5E10F5AE218CB0D2008BAB68 /* Cronet */, - 5E10F5AF218CB0D2008BAB68 /* Release */, + 5E3B95A821CAC6C500C0A151 /* Debug */, + 5E3B95A921CAC6C500C0A151 /* Test */, + 5E3B95AA21CAC6C500C0A151 /* Cronet */, + 5E3B95AB21CAC6C500C0A151 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme index b444ddc2b6..e0d1d1fdca 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/APIv2Tests.xcscheme @@ -14,7 +14,7 @@ buildForAnalyzing = "NO"> @@ -32,7 +32,7 @@ skipped = "NO"> @@ -55,7 +55,7 @@ @@ -73,7 +73,7 @@ diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index f075d9baad..e8c3e6ec2a 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -187,7 +187,7 @@ echo "TIME: $(date)" xcodebuild \ -workspace Tests.xcworkspace \ -scheme APIv2Tests \ - -destination name="iPhone X" \ + -destination name="iPhone 8" \ test \ | egrep -v "$XCODEBUILD_FILTER" \ | egrep -v '^$' \ -- cgit v1.2.3 From 1876d0d3669147e68c64d7916082de64025e9b6f Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 13:06:34 -0800 Subject: ProtoRPC bug --- src/objective-c/ProtoRPC/ProtoRPC.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 48a38bd35a..03e6839c5a 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -175,7 +175,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } - (void)writeMessage:(GPBMessage *)message { - NSAssert([message isKindOfClass:[GPBMessage class]]); + NSAssert([message isKindOfClass:[GPBMessage class]], @"Parameter message must be a GPBMessage"); if (![message isKindOfClass:[GPBMessage class]]) { NSLog(@"Failed to send a message that is non-proto."); return; @@ -199,7 +199,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { @synchronized(self) { - if (initialMetadata != nil && [_handler respondsToSelector:@selector(initialMetadata:)]) { + if (initialMetadata != nil && [_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { -- cgit v1.2.3 From 0de27b5d2955c2d19a998e133580b721836676da Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 13:08:04 -0800 Subject: More fix ProtoRPC --- src/objective-c/ProtoRPC/ProtoRPC.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 03e6839c5a..053eaf47f2 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -235,7 +235,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing } [copiedHandler didCloseWithTrailingMetadata:nil - error:ErrorForBadProto(message, _responseClass, error)]; + error:ErrorForBadProto(message, self->_responseClass, error)]; }); [_call cancel]; _call = nil; -- cgit v1.2.3 From c5f84c5cb8830ad5ac4a9f097804308adce204be Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 14:09:56 -0800 Subject: Batch fix --- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 4 ++++ src/objective-c/ProtoRPC/ProtoService.h | 6 +++--- src/objective-c/ProtoRPC/ProtoService.m | 13 +++++++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index 1a848a4b7c..7d7e77f6ba 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -292,6 +292,10 @@ gpr_free(ops_array); NSAssert(error == GRPC_CALL_OK, @"Error starting a batch of operations: %i", error); + // To avoid compiler complaint when NSAssert is disabled. + if (error != GRPC_CALL_OK) { + return; + } } } } diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index d76e96ce2a..900ec8d0e1 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -25,7 +25,7 @@ @class GRPCProtoCall; @class GRPCUnaryProtoCall; @class GRPCStreamingProtoCall; -@protocol GRPCProtoResponseCallbacks; +@protocol GRPCProtoResponseHandler; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnullability-completeness" @@ -49,12 +49,12 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoServ - (nullable GRPCUnaryProtoCall *)RPCToMethod:(nonnull NSString *)method message:(nonnull id)message - responseHandler:(nonnull id)handler + responseHandler:(nonnull id)handler callOptions:(nullable GRPCCallOptions *)callOptions responseClass:(nonnull Class)responseClass; - (nullable GRPCStreamingProtoCall *)RPCToMethod:(nonnull NSString *)method - responseHandler:(nonnull id)handler + responseHandler:(nonnull id)handler callOptions:(nullable GRPCCallOptions *)callOptions responseClass:(nonnull Class)responseClass; diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m index b7c7fadbcf..80a1f2f226 100644 --- a/src/objective-c/ProtoRPC/ProtoService.m +++ b/src/objective-c/ProtoRPC/ProtoService.m @@ -58,11 +58,14 @@ return self; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-designated-initializers" +// Do not call designated initializer here due to nullability incompatibility. This method is from +// old API and does not assert on nullability of the parameters. + - (instancetype)initWithHost:(NSString *)host packageName:(NSString *)packageName serviceName:(NSString *)serviceName { - // Do not call designated initializer here due to nullability incompatibility. This method is from - // old API and does not assert on nullability of the parameters. if ((self = [super init])) { _host = [host copy]; _packageName = [packageName copy]; @@ -72,6 +75,8 @@ return self; } +#pragma clang diagnostic pop + - (GRPCProtoCall *)RPCToMethod:(NSString *)method requestsWriter:(GRXWriter *)requestsWriter responseClass:(Class)responseClass @@ -87,7 +92,7 @@ - (GRPCUnaryProtoCall *)RPCToMethod:(NSString *)method message:(id)message - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { GRPCProtoMethod *methodName = @@ -104,7 +109,7 @@ } - (GRPCStreamingProtoCall *)RPCToMethod:(NSString *)method - responseHandler:(id)handler + responseHandler:(id)handler callOptions:(GRPCCallOptions *)callOptions responseClass:(Class)responseClass { GRPCProtoMethod *methodName = -- cgit v1.2.3 From f7ca97a6fedc4d20aab6a09b26b143a8996c9b48 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 14:15:12 -0800 Subject: clang-format --- src/objective-c/ProtoRPC/ProtoRPC.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index 053eaf47f2..0ab96a5ba2 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -199,7 +199,8 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing - (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { @synchronized(self) { - if (initialMetadata != nil && [_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) { + if (initialMetadata != nil && + [_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) { dispatch_async(_dispatchQueue, ^{ id copiedHandler = nil; @synchronized(self) { -- cgit v1.2.3 From c72a0af7816be07d3bec926f86288f9f97cb6cbd Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 16:19:48 -0800 Subject: change deployment target --- src/objective-c/tests/Tests.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index 47b79a0534..b6762cc600 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -2449,7 +2449,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -2483,7 +2483,7 @@ CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; @@ -2516,7 +2516,7 @@ CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; @@ -2549,7 +2549,7 @@ CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = APIv2Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = io.grpc.APIv2Tests; -- cgit v1.2.3 From 6cf4622cd1a721704c70be2160b6454937771141 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Dec 2018 23:15:26 -0800 Subject: provide host --- src/objective-c/tests/run_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index e8c3e6ec2a..8402809c09 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -188,6 +188,7 @@ xcodebuild \ -workspace Tests.xcworkspace \ -scheme APIv2Tests \ -destination name="iPhone 8" \ + HOST_PORT_LOCAL=localhost:5050 \ test \ | egrep -v "$XCODEBUILD_FILTER" \ | egrep -v '^$' \ -- cgit v1.2.3 From 291b4f363bbf7226eb7a3bbd7ad620f5be67c625 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 20 Dec 2018 09:52:26 -0800 Subject: More test fix --- src/objective-c/GRPCClient/GRPCCall.m | 2 +- src/objective-c/tests/run_tests.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 9bcacac0df..b0412cddb0 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -69,7 +69,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; @implementation GRPCRequestOptions - (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety { - NSAssert(host.length != 0 && path.length != 0, @"Host and Path cannot be empty"); + NSAssert(host.length != 0 && path.length != 0, @"host and path cannot be empty"); if (host.length == 0 || path.length == 0) { return nil; } diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index 8402809c09..f6fea96920 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -189,6 +189,7 @@ xcodebuild \ -scheme APIv2Tests \ -destination name="iPhone 8" \ HOST_PORT_LOCAL=localhost:5050 \ + HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \ test \ | egrep -v "$XCODEBUILD_FILTER" \ | egrep -v '^$' \ -- cgit v1.2.3 From 1f3829180c32c8c2ee1a3d546d6c2bcb3287e312 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 2 Jan 2019 15:52:42 -0800 Subject: Fix missing ConnectivityMonitor usage --- src/objective-c/GRPCClient/GRPCCall.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index b0412cddb0..83c6edc6e3 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -841,6 +841,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; [self sendHeaders]; [self invokeCall]; + + // Connectivity monitor is not required for CFStream + char *enableCFStream = getenv(kCFStreamVarName); + if (enableCFStream == nil || enableCFStream[0] != '1') { + [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)]; + } } - (void)startWithWriteable:(id)writeable { -- cgit v1.2.3 From b4a926961abc9e29016b2ba30093f3925de10514 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 4 Jan 2019 09:40:18 -0800 Subject: Fix static analizer errors --- src/objective-c/GRPCClient/GRPCCallOptions.m | 11 ++++++++--- src/objective-c/GRPCClient/private/GRPCChannelPool.h | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index d3440ee6c0..e59a812bd8 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -160,7 +160,10 @@ static BOOL areObjectsEqual(id obj1, id obj2) { _timeout = timeout < 0 ? 0 : timeout; _oauth2AccessToken = [oauth2AccessToken copy]; _authTokenProvider = authTokenProvider; - _initialMetadata = [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES]; + _initialMetadata = + initialMetadata == nil + ? nil + : [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES]; _userAgentPrefix = [userAgentPrefix copy]; _responseSizeLimit = responseSizeLimit; _compressionAlgorithm = compressionAlgorithm; @@ -171,7 +174,9 @@ static BOOL areObjectsEqual(id obj1, id obj2) { _connectInitialBackoff = connectInitialBackoff < 0 ? 0 : connectInitialBackoff; _connectMaxBackoff = connectMaxBackoff < 0 ? 0 : connectMaxBackoff; _additionalChannelArgs = - [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; + additionalChannelArgs == nil + ? nil + : [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES]; _PEMRootCertificates = [PEMRootCertificates copy]; _PEMPrivateKey = [PEMPrivateKey copy]; _PEMCertificateChain = [PEMCertificateChain copy]; @@ -458,7 +463,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { - (void)setConnectMinTimeout:(NSTimeInterval)connectMinTimeout { if (connectMinTimeout < 0) { - connectMinTimeout = 0; + _connectMinTimeout = 0; } else { _connectMinTimeout = connectMinTimeout; } diff --git a/src/objective-c/GRPCClient/private/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h index d3a99ca826..e00ee69e63 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -88,7 +88,8 @@ NS_ASSUME_NONNULL_BEGIN /** * Return a channel with a particular configuration. The channel may be a cached channel. */ -- (GRPCPooledChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions; +- (nullable GRPCPooledChannel *)channelWithHost:(NSString *)host + callOptions:(GRPCCallOptions *)callOptions; /** * Disconnect all channels in this pool. -- cgit v1.2.3