| // | |
| // Copyright 2018 Google Inc. | |
| // | |
| // 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 "Service/Sources/EDOHostNamingService.h" | |
| #import "Channel/Sources/EDOChannelPool.h" | |
| #import "Channel/Sources/EDOHostPort.h" | |
| #import "Service/Sources/EDOHostNamingService+Private.h" | |
| #import "Service/Sources/EDOHostService.h" | |
| #import "Service/Sources/EDOServicePort.h" | |
| @interface EDOHostNamingServiceProxy : NSObject | |
| - (instancetype)initWithNamingService:(EDOHostNamingService *)namingService; | |
| @end | |
| @implementation EDOHostNamingServiceProxy { | |
| __weak EDOHostNamingService *_namingService; | |
| } | |
| + (BOOL)accessInstanceVariablesDirectly { | |
| return NO; | |
| } | |
| - (instancetype)initWithNamingService:(EDOHostNamingService *)namingService { | |
| self = [super init]; | |
| if (self) { | |
| _namingService = namingService; | |
| } | |
| return self; | |
| } | |
| - (UInt16)portForServiceWithName:(NSString *)name { | |
| return [_namingService portForServiceWithName:name]; | |
| } | |
| - (UInt16)serviceConnectionPort { | |
| return _namingService.serviceConnectionPort; | |
| } | |
| @end | |
| @implementation EDOHostNamingService { | |
| // The mapping from service name to host service port. | |
| NSMutableDictionary<NSString *, EDOServicePort *> *_servicePortsInfo; | |
| // The dispatch queue to execute atomic operations of starting/stopping service and | |
| // tracking/untracking service port info. | |
| dispatch_queue_t _namingServicePortQueue; | |
| // The dispatch queue to execute service start/stop events and request handler of the naming | |
| // service. | |
| dispatch_queue_t _namingServiceEventQueue; | |
| // The host service serving the naming service object. | |
| EDOHostService *_service; | |
| } | |
| + (UInt16)namingServerPort { | |
| return 11237; | |
| } | |
| + (instancetype)sharedService { | |
| static EDOHostNamingService *instance; | |
| static dispatch_once_t onceToken; | |
| dispatch_once(&onceToken, ^{ | |
| instance = [[EDOHostNamingService alloc] initInternal]; | |
| }); | |
| return instance; | |
| } | |
| - (instancetype)initInternal { | |
| self = [super init]; | |
| if (self) { | |
| _servicePortsInfo = [[NSMutableDictionary alloc] init]; | |
| _service = nil; | |
| _namingServicePortQueue = | |
| dispatch_queue_create("com.google.edo.namingService.port", DISPATCH_QUEUE_SERIAL); | |
| _namingServiceEventQueue = | |
| dispatch_queue_create("com.google.edo.namingService.event", DISPATCH_QUEUE_SERIAL); | |
| } | |
| return self; | |
| } | |
| - (void)dealloc { | |
| [_service invalidate]; | |
| } | |
| - (UInt16)serviceConnectionPort { | |
| return EDOChannelPool.sharedChannelPool.serviceConnectionPort; | |
| } | |
| - (UInt16)portForServiceWithName:(NSString *)name { | |
| __block EDOServicePort *portInfo; | |
| dispatch_sync(_namingServicePortQueue, ^{ | |
| portInfo = self->_servicePortsInfo[name]; | |
| }); | |
| return portInfo ? portInfo.hostPort.port : 0; | |
| } | |
| - (BOOL)start { | |
| // Use a local variable to guarantee thread-safety. | |
| __block BOOL result; | |
| dispatch_sync(_namingServiceEventQueue, ^{ | |
| if (self->_service) { | |
| return; | |
| } | |
| EDOHostNamingServiceProxy *proxy = | |
| [[EDOHostNamingServiceProxy alloc] initWithNamingService:self]; | |
| self->_service = [EDOHostService serviceWithPort:EDOHostNamingService.namingServerPort | |
| rootObject:proxy | |
| queue:self->_namingServiceEventQueue]; | |
| result = self->_service.port.hostPort.port != 0; | |
| }); | |
| return result; | |
| } | |
| - (void)stop { | |
| dispatch_sync(_namingServiceEventQueue, ^{ | |
| [self->_service invalidate]; | |
| self->_service = nil; | |
| }); | |
| } | |
| #pragma mark - Private category | |
| - (BOOL)addServicePort:(EDOServicePort *)servicePort { | |
| if (!servicePort.hostPort.name) { | |
| return NO; | |
| } | |
| __block BOOL result; | |
| dispatch_sync(_namingServicePortQueue, ^{ | |
| if ([self->_servicePortsInfo objectForKey:servicePort.hostPort.name]) { | |
| result = NO; | |
| } else { | |
| [self->_servicePortsInfo setObject:servicePort forKey:servicePort.hostPort.name]; | |
| result = YES; | |
| } | |
| }); | |
| return result; | |
| } | |
| - (BOOL)removeServicePort:(EDOServicePort *)servicePort { | |
| if (!servicePort.hostPort.name) { | |
| return NO; | |
| } | |
| dispatch_sync(_namingServicePortQueue, ^{ | |
| [self->_servicePortsInfo removeObjectForKey:servicePort.hostPort.name]; | |
| }); | |
| return YES; | |
| } | |
| @end |