Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Service/Sources/EDOClientService.m
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ + (id)unwrappedObjectFromObject:(id)object {
// Otherwise, we send EDOObjectAlive message to another service running in the same process.
if ([service isObjectAliveWithPort:edoObject.servicePort
remoteAddress:edoObject.remoteAddress]) {
return (__bridge id)(void *)edoObject.remoteAddress;
id resolvedObject = [service localObjectForAddress:edoObject.remoteAddress];
if (resolvedObject) {
return resolvedObject;
}
} else if (edoObject.isLocalEdo) {
// If the underlying object is not a local object (but in the same process) then this could
// return nil. For example, the service becomes invalide, or the remote object is already
Expand Down
11 changes: 11 additions & 0 deletions Service/Sources/EDOHostService+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (BOOL)isObjectAliveWithPort:(EDOServicePort *)port remoteAddress:(EDOPointerType)remoteAddress;

/**
* Resolves the local object that this service has previously vended for the given address.
*
* The address is treated purely as an opaque lookup key into the service's tracked-object table; it
* is never dereferenced.
*
* @param remoteAddress The address that was previously returned to the client in an @c EDOObject.
* @return The tracked local object, or @c nil if @c remoteAddress is not known to this service.
*/
- (nullable id)localObjectForAddress:(EDOPointerType)remoteAddress;

/**
* Removes an EDOObject with the specified address in the host cache.
*
Expand Down
22 changes: 14 additions & 8 deletions Service/Sources/EDOHostService.m
Original file line number Diff line number Diff line change
Expand Up @@ -390,18 +390,24 @@ - (EDOObject *)distantObjectForLocalObject:(id)object hostPort:(EDOHostPort *)ho
}
}

- (BOOL)isObjectAliveWithPort:(EDOServicePort *)port remoteAddress:(EDOPointerType)remoteAddress {
if (![_port match:port]) {
return NO;
- (id)localObjectForAddress:(EDOPointerType)remoteAddress {
if (_rootLocalObject && (EDOPointerType)_rootLocalObject == remoteAddress) {
return _rootLocalObject;
}
__block BOOL isAlive;
NSNumber *edoKey = [NSNumber numberWithLongLong:remoteAddress];
__block id object;
dispatch_sync(_localObjectsSyncQueue, ^{
NSNumber *EDOKey = [NSNumber numberWithLongLong:remoteAddress];
isAlive =
self.localObjects[EDOKey] != nil || ((EDOPointerType)self.rootLocalObject) == remoteAddress;
object = self.localObjects[edoKey];
});
return object;
}

- (BOOL)isObjectAliveWithPort:(EDOServicePort *)port remoteAddress:(EDOPointerType)remoteAddress {
// ivar is used directly here to avoid the service lazily creating listen port.
return isAlive;
if (![_port match:port]) {
return NO;
}
return [self localObjectForAddress:remoteAddress] != nil;
}

- (BOOL)removeObjectWithAddress:(EDOPointerType)remoteAddress {
Expand Down
16 changes: 15 additions & 1 deletion Service/Sources/EDOInvocationMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,21 @@ + (EDORequestHandler)requestHandler {
NSAssert([request isKindOfClass:[EDOInvocationRequest class]],
@"EDOInvocationRequest is expected.");
EDOHostPort *hostPort = request.hostPort;
id target = (__bridge id)(void *)request.target;
id target = [service localObjectForAddress:request.target];
if (!target) {
NSString *reason =
[NSString stringWithFormat:@"The target address (%llx) is not tracked by this service.",
request.target];
EDORemoteException *remoteException =
[[EDORemoteException alloc] initWithName:EDOServiceGenericException
reason:reason
callStackSymbols:@[]];
return [EDOInvocationResponse responseWithReturnValue:nil
exception:remoteException
outValues:nil
forRequest:request
targetClass:Nil];
}
SEL sel = NSSelectorFromString(request.selectorName);

EDOBoxedValueType *returnValue;
Expand Down
6 changes: 5 additions & 1 deletion Service/Sources/EDOMethodSignatureMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#import "Service/Sources/EDOMethodSignatureMessage.h"

#import "Service/Sources/EDOHostService+Private.h"
#import "Service/Sources/EDOHostService.h"
#import "Service/Sources/EDOMessage.h"
#import "Service/Sources/EDOObject+Private.h"
Expand Down Expand Up @@ -97,7 +98,10 @@ + (EDORequestHandler)requestHandler {
}

EDOMethodSignatureRequest *methodRequest = (EDOMethodSignatureRequest *)request;
id object = (__bridge Class)(void *)methodRequest.object;
id object = [service localObjectForAddress:methodRequest.object];
if (!object) {
return [[EDOMethodSignatureResponse alloc] initWithSignature:nil forRequest:request];
}
SEL sel = NSSelectorFromString(methodRequest.selectorName);

NSMethodSignature *signature = EDOGetMethodSignature(object, sel);
Expand Down
75 changes: 75 additions & 0 deletions Service/Tests/UnitTests/EDOMessageTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#import "Service/Sources/EDOObjectMessage.h"
#import "Service/Sources/EDOParameter.h" // IWYU pragma: keep
#import "Service/Sources/EDORemoteException.h"
#import "Service/Sources/EDOServiceException.h"
#import "Service/Sources/EDOServicePort.h"

#import "Service/Tests/TestsBundle/EDOTestDummy.h"
Expand Down Expand Up @@ -435,6 +436,9 @@ - (void)testClassMethodInvocationHandler {
EDOTestDummy *dummyLocal = [[EDOTestDummy alloc] init];
[self edo_createQueueAndServiceWithRootObject:dummyLocal
block:^(EDOHostService *service) {
[service
distantObjectForLocalObject:[dummyLocal class]
hostPort:service.port.hostPort];
EDOInvocationResponse *response = [self
edo_runInvocationWithService:service
target:[dummyLocal class]
Expand Down Expand Up @@ -509,6 +513,7 @@ - (void)testMethodSignatureRequestHandler {
EDOHostService *service = [EDOHostService serviceWithPort:0
rootObject:self
queue:dispatch_get_main_queue()];
[service distantObjectForLocalObject:dummyLocal hostPort:service.port.hostPort];

[EDOTestDummy enumerateSelector:^(SEL selector) {
EDOMethodSignatureRequest *request =
Expand All @@ -531,6 +536,76 @@ - (void)testMethodSignatureRequestHandler {
[service invalidate];
}

- (void)testUntrackedTargetInvocationHandlerReturnsException {
XCTestExpectation *blockExecuted = [self expectationWithDescription:@"Executed the test block."];
EDOTestDummy *dummyLocal = [[EDOTestDummy alloc] init];
[self edo_createQueueAndServiceWithRootObject:dummyLocal
block:^(EDOHostService *service) {
EDOPointerType bogusAddress =
(EDOPointerType)0x4141414141414140LL;
EDOInvocationRequest *request = [EDOInvocationRequest
requestWithTarget:bogusAddress
selector:@selector(returnInt)
arguments:@[]
hostPort:service.port.hostPort
returnByValue:NO];
EDOInvocationResponse *response =
(EDOInvocationResponse *)EDOInvocationRequest
.requestHandler(request, service);
XCTAssertNil(response.returnValue);
XCTAssertEqualObjects(response.exception.name,
EDOServiceGenericException);
[blockExecuted fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
}

- (void)testReleasedTargetInvocationHandlerReturnsException {
XCTestExpectation *blockExecuted = [self expectationWithDescription:@"Executed the test block."];
EDOTestDummy *rootLocal = [[EDOTestDummy alloc] init];
[self edo_createQueueAndServiceWithRootObject:rootLocal
block:^(EDOHostService *service) {
EDOPointerType releasedAddress = 0;
@autoreleasepool {
EDOTestDummy *transient = [[EDOTestDummy alloc] init];
EDOObject *proxy =
[service distantObjectForLocalObject:transient
hostPort:nil];
releasedAddress = proxy.remoteAddress;
[service removeObjectWithAddress:releasedAddress];
}
EDOInvocationRequest *request = [EDOInvocationRequest
requestWithTarget:releasedAddress
selector:@selector(returnInt)
arguments:@[]
hostPort:service.port.hostPort
returnByValue:NO];
EDOInvocationResponse *response =
(EDOInvocationResponse *)EDOInvocationRequest
.requestHandler(request, service);
XCTAssertNil(response.returnValue);
XCTAssertEqualObjects(response.exception.name,
EDOServiceGenericException);
[blockExecuted fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
}

- (void)testUntrackedObjectMethodSignatureRequestHandlerReturnsNil {
EDOHostService *service = [EDOHostService serviceWithPort:0
rootObject:self
queue:dispatch_get_main_queue()];
EDOPointerType bogusAddress = (EDOPointerType)0x4141414141414140LL;
EDOMethodSignatureRequest *request =
[EDOMethodSignatureRequest requestWithObject:bogusAddress
port:service.port
selector:@selector(description)];
EDOMethodSignatureResponse *response =
(EDOMethodSignatureResponse *)EDOMethodSignatureRequest.requestHandler(request, service);
XCTAssertNil(response.signature);
[service invalidate];
}

- (void)testMethodSignatureForward {
id dummyLocal = [[EDOTestDummy alloc] init];
NS_VALID_UNTIL_END_OF_SCOPE dispatch_queue_t queue =
Expand Down
Loading