mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
7.5 KiB
Objective-C
191 lines
7.5 KiB
Objective-C
#import <XCTest/XCTest.h>
|
|
#import <CoreFoundation/CFSocket.h>
|
|
#import "IpAddress.h"
|
|
#import "TestUtil.h"
|
|
#import "ThreadManager.h"
|
|
#import "UdpSocket.h"
|
|
#import "Util.h"
|
|
|
|
@interface UdpSocketTest : XCTestCase
|
|
|
|
@end
|
|
|
|
@implementation UdpSocketTest
|
|
-(void) testSpecifiedPortLocally {
|
|
TOCCancelTokenSource* receiverLife = [TOCCancelTokenSource new];
|
|
TOCCancelTokenSource* senderLife = [TOCCancelTokenSource new];
|
|
|
|
__block NSData* received = nil;
|
|
__block bool senderReceivedData = false;
|
|
NSData* r1 = [@[@2,@3,@5] ows_toUint8Data];
|
|
NSData* r2 = [@[@7,@11,@13] ows_toUint8Data];
|
|
NSData* r3 = [@[@17,@19,@23] ows_toUint8Data];
|
|
|
|
in_port_t port1 = (in_port_t)(arc4random_uniform(40000) + 10000);
|
|
in_port_t port2 = port1 + (in_port_t)1;
|
|
|
|
UdpSocket* receiver = [UdpSocket udpSocketFromLocalPort:port1 toRemoteEndPoint:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:port2]];
|
|
UdpSocket* sender = [UdpSocket udpSocketFromLocalPort:port2 toRemoteEndPoint:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:port1]];
|
|
[receiver startWithHandler:[PacketHandler packetHandler:^(id packet) {
|
|
received = packet;
|
|
} withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
|
|
test(false);
|
|
}] untilCancelled:receiverLife.token];
|
|
__block bool failed = false;
|
|
[sender startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
|
|
// there's a length check here because when the destination is unreachable the sender sometimes gets a superfluous empty data callback... no idea why.
|
|
senderReceivedData |= packet.length > 0;
|
|
} withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
|
|
failed = true;
|
|
}] untilCancelled:senderLife.token];
|
|
|
|
test(receiver.isLocalPortKnown);
|
|
test(receiver.localPort == port1);
|
|
test(sender.isLocalPortKnown);
|
|
test(sender.localPort == port2);
|
|
|
|
testChurnAndConditionMustStayTrue(received == nil, 0.1);
|
|
|
|
[sender send:r1];
|
|
testChurnUntil([received isEqualToData:r1], 1.0);
|
|
test([received isEqualToData:r1]);
|
|
|
|
[sender send:r2];
|
|
testChurnUntil([received isEqualToData:r2], 1.0);
|
|
|
|
[receiverLife cancel];
|
|
test(!failed);
|
|
[sender send:r3];
|
|
testChurnUntil(failed, 1.0);
|
|
test([received isEqualToData:r2]);
|
|
|
|
[senderLife cancel];
|
|
test(!senderReceivedData);
|
|
}
|
|
-(void) testArbitraryPortLocally {
|
|
TOCCancelTokenSource* receiverLife = [TOCCancelTokenSource new];
|
|
TOCCancelTokenSource* senderLife = [TOCCancelTokenSource new];
|
|
|
|
__block NSData* received = nil;
|
|
__block bool senderReceivedData = false;
|
|
NSData* r1 = [@[@2,@3,@5] ows_toUint8Data];
|
|
NSData* r2 = [@[@7,@11,@13] ows_toUint8Data];
|
|
NSData* r3 = [@[@17,@19,@23] ows_toUint8Data];
|
|
|
|
in_port_t unusedPort = (in_port_t)(arc4random_uniform(40000) + 10000);
|
|
|
|
UdpSocket* receiver = [UdpSocket udpSocketTo:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost
|
|
onPort:unusedPort]];
|
|
[receiver startWithHandler:[PacketHandler packetHandler:^(id packet) {
|
|
@synchronized (churnLock()) {
|
|
received = packet;
|
|
}
|
|
} withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
|
|
test(false);
|
|
}] untilCancelled:receiverLife.token];
|
|
|
|
__block bool failed = false;
|
|
UdpSocket* sender = [UdpSocket udpSocketFromLocalPort:unusedPort
|
|
toRemoteEndPoint:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost
|
|
onPort:receiver.localPort]];
|
|
[sender startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
|
|
// there's a length check here because when the destination is unreachable the sender sometimes gets a superfluous empty data callback... no idea why.
|
|
senderReceivedData |= packet.length > 0;
|
|
} withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
|
|
failed = true;
|
|
}] untilCancelled:senderLife.token];
|
|
|
|
|
|
testChurnAndConditionMustStayTrue(received == nil, 0.1);
|
|
|
|
[sender send:r1];
|
|
testChurnUntil([received isEqualToData:r1], 1.0);
|
|
|
|
[sender send:r2];
|
|
testChurnUntil([received isEqualToData:r2], 1.0);
|
|
|
|
[receiverLife cancel];
|
|
test(!failed);
|
|
[sender send:r3];
|
|
testChurnAndConditionMustStayTrue([received isEqualToData:r2], 0.1);
|
|
test([received isEqualToData:r2]);
|
|
|
|
[senderLife cancel];
|
|
test(!senderReceivedData);
|
|
}
|
|
-(void) testUdpListen {
|
|
TOCCancelTokenSource* receiverLife = [TOCCancelTokenSource new];
|
|
TOCCancelTokenSource* senderLife = [TOCCancelTokenSource new];
|
|
|
|
__block NSUInteger listenerReceiveCount = 0;
|
|
__block NSUInteger listenerReceiveLength = 0;
|
|
__block NSData* listenerReceivedLast = nil;
|
|
__block NSUInteger clientReceiveCount = 0;
|
|
__block NSUInteger clientReceiveLength = 0;
|
|
__block NSData* clientReceivedLast = nil;
|
|
|
|
in_port_t port = (in_port_t)(arc4random_uniform(40000) + 10000);
|
|
|
|
UdpSocket* listener = [UdpSocket udpSocketToFirstSenderOnLocalPort:port];
|
|
[listener startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
|
|
listenerReceiveCount += 1;
|
|
listenerReceiveLength += packet.length;
|
|
listenerReceivedLast = packet;
|
|
} withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
|
|
test(false);
|
|
}] untilCancelled:receiverLife.token];
|
|
|
|
IpEndPoint* e = [IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:port];
|
|
UdpSocket* client = [UdpSocket udpSocketTo:e];
|
|
[client startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
|
|
clientReceiveCount += 1;
|
|
clientReceiveLength += packet.length;
|
|
clientReceivedLast = packet;
|
|
} withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
|
|
test(false);
|
|
}] untilCancelled:senderLife.token];
|
|
|
|
test(!listener.isRemoteEndPointKnown);
|
|
testThrows([listener remoteEndPoint]);
|
|
test(client.isRemoteEndPointKnown);
|
|
test([client remoteEndPoint] == e);
|
|
test(listenerReceiveCount == 0);
|
|
test(clientReceiveCount == 0);
|
|
|
|
[client send:increasingData(10)];
|
|
testChurnUntil(listenerReceiveCount > 0, 1.0);
|
|
test(clientReceiveCount == 0);
|
|
test(listener.isRemoteEndPointKnown);
|
|
test([[[[listener remoteEndPoint] address] description] isEqualToString:@"127.0.0.1"]);
|
|
test(listenerReceiveLength == 10);
|
|
test([listenerReceivedLast isEqualToData:increasingData(10)]);
|
|
|
|
[listener send:increasingData(20)];
|
|
testChurnUntil(clientReceiveCount > 0, 1.0);
|
|
test(listenerReceiveCount == 1);
|
|
test(clientReceiveCount == 1);
|
|
test(clientReceiveLength == 20);
|
|
test([clientReceivedLast isEqualToData:increasingData(20)]);
|
|
|
|
[receiverLife cancel];
|
|
[senderLife cancel];
|
|
}
|
|
-(void) testUdpFail {
|
|
TOCCancelTokenSource* life = [TOCCancelTokenSource new];
|
|
|
|
in_port_t unusedPort = 10000 + (in_port_t)arc4random_uniform(30000);
|
|
UdpSocket* udp = [UdpSocket udpSocketTo:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:unusedPort]];
|
|
__block bool failed = false;
|
|
[udp startWithHandler:[PacketHandler packetHandler:^(id packet) {
|
|
test(false);
|
|
} withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
|
|
failed = true;
|
|
}] untilCancelled:life.token];
|
|
|
|
[udp send:increasingData(20)];
|
|
testChurnUntil(failed, 1.0);
|
|
|
|
[life cancel];
|
|
}
|
|
@end
|