mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Add PSK support in Wifi common implementation
PiperOrigin-RevId: 758744875
This commit is contained in:
committed by
Copybara-Service
parent
3c718941b1
commit
cc1239789f
@@ -14,6 +14,8 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class GNCIPv4Address;
|
||||
@class GNCNWFrameworkServerSocket;
|
||||
@class GNCNWFrameworkSocket;
|
||||
@@ -55,6 +57,31 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName,
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/**
|
||||
* Listens for incoming connections with PSK based TLS on a given port.
|
||||
*
|
||||
* This function will always be called before a call to
|
||||
* startAdvertisingServiceName:serviceType:error:, but may also be called on its own without a call
|
||||
* to start advertising the service. This function will also be called during upgrade attempts on
|
||||
* the advertising side.
|
||||
*
|
||||
* This function should block execution until ready for incoming connections.
|
||||
*
|
||||
* @param port The port on which the listener can accept connections. Should be a number between 1
|
||||
* and 65536 to open a server socket on that exact port. Zero can be used to listen on
|
||||
* a random port.
|
||||
* @param PSKIdentity The PSK identity of the service.
|
||||
* @param PSKSharedSecret The PSK shared secret of the service.
|
||||
* @param includePeerToPeer Whether to include peer-to-peer services.
|
||||
* @param[out] error Error that will be populated on failure.
|
||||
* @return Returns a server socket or nil if an error has occured.
|
||||
*/
|
||||
- (nullable GNCNWFrameworkServerSocket *)listenForServiceWithPSKIdentity:(NSData *)PSKIdentity
|
||||
PSKSharedSecret:(NSData *)PSKSharedSecret
|
||||
port:(NSInteger)port
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/**
|
||||
* Creates a Bonjour service that advertises the listener on the local network.
|
||||
*
|
||||
@@ -64,9 +91,9 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName,
|
||||
* @param txtRecords The TXT record to advertise with the service.
|
||||
*/
|
||||
- (void)startAdvertisingPort:(NSInteger)port
|
||||
serviceName:(nonnull NSString *)serviceName
|
||||
serviceType:(nonnull NSString *)serviceType
|
||||
txtRecords:(nonnull NSDictionary<NSString *, NSString *> *)txtRecords;
|
||||
serviceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
txtRecords:(NSDictionary<NSString *, NSString *> *)txtRecords;
|
||||
|
||||
/**
|
||||
* Removes the Bonjour service advertisement.
|
||||
@@ -85,7 +112,7 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName,
|
||||
* @param[out] error Error that will be populated on failure.
|
||||
* @return Returns YES when discovery has successfully started.
|
||||
*/
|
||||
- (BOOL)startDiscoveryForServiceType:(nonnull NSString *)serviceType
|
||||
- (BOOL)startDiscoveryForServiceType:(NSString *)serviceType
|
||||
serviceFoundHandler:(ServiceUpdateHandler)serviceFoundHandler
|
||||
serviceLostHandler:(ServiceUpdateHandler)serviceLostHandler
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
@@ -96,7 +123,7 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName,
|
||||
*
|
||||
* @param serviceType The Bonjour type of the service.
|
||||
*/
|
||||
- (void)stopDiscoveryForServiceType:(nonnull NSString *)serviceType;
|
||||
- (void)stopDiscoveryForServiceType:(NSString *)serviceType;
|
||||
|
||||
/**
|
||||
* Connects to a Bonjour service.
|
||||
@@ -106,8 +133,24 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName,
|
||||
* @param[out] error Error that will be populated on failure.
|
||||
* @return Returns a connected socket or nil if an error has occured.
|
||||
*/
|
||||
- (nullable GNCNWFrameworkSocket *)connectToServiceName:(nonnull NSString *)serviceName
|
||||
serviceType:(nonnull NSString *)serviceType
|
||||
- (nullable GNCNWFrameworkSocket *)connectToServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/**
|
||||
* Connects to a Bonjour service with PSK based TLS.
|
||||
*
|
||||
* @param serviceName The Bonjour name of the service.
|
||||
* @param serviceType The Bonjour type of the service.
|
||||
* @param PSKIdentity The PSK identity of the service.
|
||||
* @param PSKSharedSecret The PSK shared secret of the service.
|
||||
* @param[out] error Error that will be populated on failure.
|
||||
* @return Returns a connected socket or nil if an error has occured.
|
||||
*/
|
||||
- (nullable GNCNWFrameworkSocket *)connectToServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
PSKIdentity:(NSData *)PSKIdentity
|
||||
PSKSharedSecret:(NSData *)PSKSharedSecret
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/**
|
||||
@@ -119,7 +162,7 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName,
|
||||
* @param[out] error Error that will be populated on failure.
|
||||
* @return Returns a connected socket or nil if an error has occured.
|
||||
*/
|
||||
- (nullable GNCNWFrameworkSocket *)connectToHost:(nonnull GNCIPv4Address *)host
|
||||
- (nullable GNCNWFrameworkSocket *)connectToHost:(GNCIPv4Address *)host
|
||||
port:(NSInteger)port
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **_Nullable)error;
|
||||
@@ -134,3 +177,5 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName,
|
||||
*/
|
||||
- (BOOL)isDiscoveringAnyService;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkServerSocket+Internal.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkServerSocket.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWParameters.h"
|
||||
#import "GoogleToolboxForMac/GTMLogger.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// An arbitrary timeout that should be pretty lenient.
|
||||
NSTimeInterval const GNCConnectionTimeoutInSeconds = 2;
|
||||
|
||||
@@ -60,6 +63,14 @@ NSDictionary<NSString *, NSString *> *GNCTXTRecordForBrowseResult(nw_browse_resu
|
||||
return txtRecords;
|
||||
}
|
||||
|
||||
@interface GNCNWFramework ()
|
||||
- (nullable GNCNWFrameworkSocket *)internalConnectToEndpoint:(nw_endpoint_t)endpoint
|
||||
PSKIdentity:(nullable NSData *)PSKIdentity
|
||||
PSKSharedSecret:(nullable NSData *)PSKSharedSecret
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@implementation GNCNWFramework {
|
||||
// Holds a weak reference to a server socket that is retrievable by port. This allows us to stop
|
||||
// advertisements for a given port without taking a strong reference. This keeps the ownership
|
||||
@@ -111,9 +122,9 @@ static GNCNWFramework *gInstance = nil;
|
||||
return _serviceBrowsers.count > 0;
|
||||
}
|
||||
|
||||
- (GNCNWFrameworkServerSocket *)listenForServiceOnPort:(NSInteger)port
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **)error {
|
||||
- (nullable GNCNWFrameworkServerSocket *)listenForServiceOnPort:(NSInteger)port
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **)error {
|
||||
GTMLoggerInfo(@"[GNCNWFramework] Listen on port: %ld with includePeerToPeer: %@.", (long)port,
|
||||
(includePeerToPeer ? @"true" : @"false"));
|
||||
GNCNWFrameworkServerSocket *serverSocket = [[GNCNWFrameworkServerSocket alloc] initWithPort:port];
|
||||
@@ -126,6 +137,28 @@ static GNCNWFramework *gInstance = nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable GNCNWFrameworkServerSocket *)listenForServiceWithPSKIdentity:(NSData *)PSKIdentity
|
||||
PSKSharedSecret:(NSData *)PSKSharedSecret
|
||||
port:(NSInteger)port
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:
|
||||
(NSError **_Nullable)error {
|
||||
GTMLoggerInfo(
|
||||
@"[GNCNWFramework] Listen on port: %ld with includePeerToPeer: %@, and PSKIdentity: %@.",
|
||||
(long)port, (includePeerToPeer ? @"true" : @"false"), PSKIdentity);
|
||||
GNCNWFrameworkServerSocket *serverSocket = [[GNCNWFrameworkServerSocket alloc] initWithPort:port];
|
||||
_includePeerToPeer = includePeerToPeer;
|
||||
BOOL success = [serverSocket startListeningWithPSKIdentity:PSKIdentity
|
||||
PSKSharedSecret:PSKSharedSecret
|
||||
includePeerToPeer:_includePeerToPeer
|
||||
error:error];
|
||||
if (success) {
|
||||
[_serverSockets setObject:serverSocket forKey:@(serverSocket.port)];
|
||||
return serverSocket;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)startAdvertisingPort:(NSInteger)port
|
||||
serviceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
@@ -158,11 +191,12 @@ static GNCNWFramework *gInstance = nil;
|
||||
|
||||
// Create a parameters object configured to support TCP. TLS MUST be disabled for Nearby to
|
||||
// function properly.
|
||||
nw_parameters_t parameters =
|
||||
nw_parameters_create_secure_tcp(/*tls*/ NW_PARAMETERS_DISABLE_PROTOCOL,
|
||||
/*tcp*/ NW_PARAMETERS_DEFAULT_CONFIGURATION);
|
||||
_includePeerToPeer = includePeerToPeer;
|
||||
nw_parameters_set_include_peer_to_peer(parameters, _includePeerToPeer);
|
||||
nw_parameters_t parameters = GNCBuildNonTLSParameters(/*includePeerToPeer=*/_includePeerToPeer);
|
||||
if (!parameters) {
|
||||
GTMLoggerError(@"[GNCNWFramework] Failed to create NW parameters.");
|
||||
return NO;
|
||||
}
|
||||
nw_browse_descriptor_t descriptor =
|
||||
nw_browse_descriptor_create_bonjour_service([serviceType UTF8String], /*domain=*/nil);
|
||||
nw_browse_descriptor_set_include_txt_record(descriptor, YES);
|
||||
@@ -287,42 +321,76 @@ static GNCNWFramework *gInstance = nil;
|
||||
nw_browser_cancel(browser);
|
||||
}
|
||||
|
||||
- (GNCNWFrameworkSocket *)connectToServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
error:(NSError **)error {
|
||||
- (nullable GNCNWFrameworkSocket *)connectToServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
error:(NSError **)error {
|
||||
GTMLoggerInfo(@"[GNCNWFramework] Connect to service {serviceName:%@, serviceType:%@, "
|
||||
@"includePeerToPeer:%@}.",
|
||||
serviceName, serviceType, (_includePeerToPeer ? @"true" : @"false"));
|
||||
nw_endpoint_t endpoint = nw_endpoint_create_bonjour_service([serviceName UTF8String],
|
||||
[serviceType UTF8String], "local");
|
||||
return [self connectToEndpoint:endpoint includePeerToPeer:_includePeerToPeer error:error];
|
||||
return [self internalConnectToEndpoint:endpoint
|
||||
PSKIdentity:nil
|
||||
PSKSharedSecret:nil
|
||||
includePeerToPeer:_includePeerToPeer
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (GNCNWFrameworkSocket *)connectToHost:(GNCIPv4Address *)host
|
||||
port:(NSInteger)port
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **)error {
|
||||
- (nullable GNCNWFrameworkSocket *)connectToServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
PSKIdentity:(NSData *)PSKIdentity
|
||||
PSKSharedSecret:(NSData *)PSKSharedSecret
|
||||
error:(NSError **_Nullable)error {
|
||||
GTMLoggerInfo(@"[GNCNWFramework] Connect to service {serviceName:%@, serviceType:%@, "
|
||||
@"includePeerToPeer:%@}.",
|
||||
serviceName, serviceType, (_includePeerToPeer ? @"true" : @"false"));
|
||||
nw_endpoint_t endpoint = nw_endpoint_create_bonjour_service([serviceName UTF8String],
|
||||
[serviceType UTF8String], "local");
|
||||
return [self internalConnectToEndpoint:endpoint
|
||||
PSKIdentity:PSKIdentity
|
||||
PSKSharedSecret:PSKSharedSecret
|
||||
includePeerToPeer:_includePeerToPeer
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (nullable GNCNWFrameworkSocket *)connectToHost:(GNCIPv4Address *)host
|
||||
port:(NSInteger)port
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **)error {
|
||||
GTMLoggerInfo(@"[GNCNWFramework] Connect to host {host:%s, port:%ld}.",
|
||||
host.dottedRepresentation.UTF8String, (long)port);
|
||||
nw_endpoint_t endpoint =
|
||||
nw_endpoint_create_host(host.dottedRepresentation.UTF8String, @(port).stringValue.UTF8String);
|
||||
return [self connectToEndpoint:endpoint includePeerToPeer:(BOOL)includePeerToPeer error:error];
|
||||
return [self internalConnectToEndpoint:endpoint
|
||||
PSKIdentity:nil
|
||||
PSKSharedSecret:nil
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (GNCNWFrameworkSocket *)connectToEndpoint:(nw_endpoint_t)endpoint
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **)error {
|
||||
// MARK: - Private Methods (Implementation)
|
||||
|
||||
- (nullable GNCNWFrameworkSocket *)internalConnectToEndpoint:(nw_endpoint_t)endpoint
|
||||
PSKIdentity:(nullable NSData *)PSKIdentity
|
||||
PSKSharedSecret:(nullable NSData *)PSKSharedSecret
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **)error {
|
||||
NSCondition *condition = [[NSCondition alloc] init];
|
||||
[condition lock];
|
||||
|
||||
__block nw_connection_state_t blockResult = nw_connection_state_invalid;
|
||||
__block NSError *blockError = nil;
|
||||
|
||||
nw_parameters_t parameters =
|
||||
nw_parameters_create_secure_tcp(/*tls*/ NW_PARAMETERS_DISABLE_PROTOCOL,
|
||||
/*tcp*/ NW_PARAMETERS_DEFAULT_CONFIGURATION);
|
||||
_includePeerToPeer = includePeerToPeer;
|
||||
nw_parameters_set_include_peer_to_peer(parameters, _includePeerToPeer);
|
||||
nw_parameters_t parameters =
|
||||
(PSKIdentity == nil || PSKSharedSecret == nil)
|
||||
? GNCBuildNonTLSParameters(/*includePeerToPeer=*/_includePeerToPeer)
|
||||
: GNCBuildTLSParameters(/*PSK=*/PSKSharedSecret, /*identity=*/PSKIdentity,
|
||||
/*includePeerToPeer=*/_includePeerToPeer);
|
||||
if (!parameters) {
|
||||
GTMLoggerError(@"[GNCNWFramework] Failed to create NW parameters.");
|
||||
return nil;
|
||||
}
|
||||
nw_connection_t connection = nw_connection_create(endpoint, parameters);
|
||||
nw_connection_set_queue(connection, dispatch_get_main_queue());
|
||||
nw_connection_set_state_changed_handler(
|
||||
@@ -373,3 +441,5 @@ static GNCNWFramework *gInstance = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
+26
-4
@@ -16,6 +16,8 @@
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkServerSocket.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GNCNWFrameworkServerSocket (Internal)
|
||||
|
||||
/**
|
||||
@@ -28,7 +30,25 @@
|
||||
* @param[out] error Error that will be populated on failure.
|
||||
* @return Returns YES when listening has successfully started.
|
||||
*/
|
||||
- (BOOL)startListeningWithError:(NSError **_Nullable)error includePeerToPeer:(BOOL)peerToPeer;
|
||||
- (BOOL)startListeningWithError:(NSError **_Nullable)error
|
||||
includePeerToPeer:(BOOL)includePeerToPeer;
|
||||
|
||||
/**
|
||||
* Starts listening for inbound connections with a PSK identity and shared secret.
|
||||
*
|
||||
* Blocks execution until listening has started or failed.
|
||||
*
|
||||
* @param PSKIdentity The PSK identity to use for the connection.
|
||||
* @param PSKSharedSecret The PSK shared secret to use for the connection.
|
||||
* @param includePeerToPeer Indicates if the server should be configured for peer-to-peer
|
||||
* connections.
|
||||
* @param[out] error Error that will be populated on failure.
|
||||
* @return Returns YES when listening has successfully started.
|
||||
*/
|
||||
- (BOOL)startListeningWithPSKIdentity:(NSData *)PSKIdentify
|
||||
PSKSharedSecret:(NSData *)PSKSharedSecret
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/**
|
||||
* Creates a Bonjour service that advertises the listener on the local network.
|
||||
@@ -37,9 +57,9 @@
|
||||
* @param serviceType The Bonjour type of the service.
|
||||
* @param txtRecords The TXT record to advertise with the service.
|
||||
*/
|
||||
- (void)startAdvertisingServiceName:(nonnull NSString *)serviceName
|
||||
serviceType:(nonnull NSString *)serviceType
|
||||
txtRecords:(nonnull NSDictionary<NSString *, NSString *> *)txtRecords;
|
||||
- (void)startAdvertisingServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
txtRecords:(NSDictionary<NSString *, NSString *> *)txtRecords;
|
||||
|
||||
/**
|
||||
* Removes the Bonjour service advertisement.
|
||||
@@ -47,3 +67,5 @@
|
||||
- (void)stopAdvertising;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
+6
-2
@@ -14,6 +14,8 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class GNCIPv4Address;
|
||||
@class GNCNWFrameworkSocket;
|
||||
|
||||
@@ -22,14 +24,14 @@
|
||||
/**
|
||||
* @remark init is not an available initializer.
|
||||
*/
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Creates a server socket for a given port.
|
||||
*
|
||||
* @param port The port of the server socket.
|
||||
*/
|
||||
- (nonnull instancetype)initWithPort:(NSInteger)port NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithPort:(NSInteger)port NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* The IPv4 address of the physical network interface.
|
||||
@@ -62,3 +64,5 @@
|
||||
- (void)close;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
+112
-80
@@ -26,13 +26,21 @@
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkError.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkServerSocket+Internal.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWParameters.h"
|
||||
#import "GoogleToolboxForMac/GTMLogger.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GNCNWFrameworkServerSocket ()
|
||||
|
||||
@property(nonatomic, readonly) NSMutableArray<nw_connection_t> *pendingConnections;
|
||||
@property(nonatomic, readonly) NSMutableArray<nw_connection_t> *readyConnections;
|
||||
|
||||
- (BOOL)internalStartListeningWithPSKIdentity:(nullable NSData *)PSKIdentify
|
||||
PSKSharedSecret:(nullable NSData *)PSKSharedSecret
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCNWFrameworkServerSocket {
|
||||
@@ -81,7 +89,7 @@
|
||||
return _ipAddress;
|
||||
}
|
||||
|
||||
- (GNCNWFrameworkSocket *)acceptWithError:(NSError **)error {
|
||||
- (nullable GNCNWFrameworkSocket *)acceptWithError:(NSError **)error {
|
||||
// Wait until we have a ready connection and listener is in a ready/invalid state.
|
||||
[_condition lock];
|
||||
nw_connection_t connection = [self.readyConnections lastObject];
|
||||
@@ -113,16 +121,108 @@
|
||||
}
|
||||
|
||||
- (BOOL)startListeningWithError:(NSError **)error includePeerToPeer:(BOOL)includePeerToPeer {
|
||||
// Create a parameters object configured to support TCP. TLS MUST be disabled for Nearby to
|
||||
// function properly.
|
||||
nw_parameters_t parameters =
|
||||
nw_parameters_create_secure_tcp(/*tls*/ NW_PARAMETERS_DISABLE_PROTOCOL,
|
||||
/*tcp*/ NW_PARAMETERS_DEFAULT_CONFIGURATION);
|
||||
nw_parameters_set_include_peer_to_peer(parameters, includePeerToPeer);
|
||||
return [self internalStartListeningWithPSKIdentity:nil
|
||||
PSKSharedSecret:nil
|
||||
includePeerToPeer:includePeerToPeer
|
||||
error:error];
|
||||
}
|
||||
|
||||
// If the server socket port is zero, a random port will be selected. The server socket port will
|
||||
// be updated to reflect the port it's listening on, once the listener transitions to the ready
|
||||
// state.
|
||||
- (BOOL)startListeningWithPSKIdentity:(NSData *)PSKIdentify
|
||||
PSKSharedSecret:(NSData *)PSKSharedSecret
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **_Nullable)error {
|
||||
return [self internalStartListeningWithPSKIdentity:PSKIdentify
|
||||
PSKSharedSecret:PSKSharedSecret
|
||||
includePeerToPeer:includePeerToPeer
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (void)startAdvertisingServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
txtRecords:(NSDictionary<NSString *, NSString *> *)txtRecords {
|
||||
GTMLoggerInfo(@"[GNCNWFrameworkServerSocket] Start advertising {serviceName:%@, "
|
||||
@"serviceType: %@}",
|
||||
serviceName, serviceType);
|
||||
|
||||
nw_advertise_descriptor_t advertiseDescriptor = nw_advertise_descriptor_create_bonjour_service(
|
||||
[serviceName UTF8String], [serviceType UTF8String], /*domain=*/nil);
|
||||
nw_txt_record_t txtRecord = nw_txt_record_create_dictionary();
|
||||
for (NSString *key in txtRecords) {
|
||||
NSString *recordValue = [txtRecords objectForKey:key];
|
||||
NSData *encodedRecord = [recordValue dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (!nw_txt_record_set_key(txtRecord, [key UTF8String], encodedRecord.bytes,
|
||||
encodedRecord.length)) {
|
||||
GTMLoggerError(@"[GNCNWFrameworkServerSocket] Failed to set text record key: %@, value: %@",
|
||||
key, recordValue);
|
||||
continue;
|
||||
}
|
||||
GTMLoggerDebug(@"[GNCNWFrameworkServerSocket] Text record {key: "
|
||||
@"%@, value: %@}",
|
||||
key, recordValue);
|
||||
}
|
||||
nw_advertise_descriptor_set_txt_record_object(advertiseDescriptor, txtRecord);
|
||||
nw_listener_set_advertise_descriptor(_listener, advertiseDescriptor);
|
||||
}
|
||||
|
||||
- (void)stopAdvertising {
|
||||
nw_listener_set_advertise_descriptor(_listener, nil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attemps to find an IPv4 hostname for a Wi-Fi/Ethernet interface.
|
||||
*
|
||||
* Returns the IP address as a 4 byte string. If not available, this returns an empty string to
|
||||
* align with the Windows implementation.
|
||||
*/
|
||||
+ (GNCIPv4Address *)lookupIpAddress {
|
||||
GNCIPv4Address *result = [GNCIPv4Address addressFromFourByteInt:0];
|
||||
struct ifaddrs *ifaddr;
|
||||
if (getifaddrs(&ifaddr) == 0) {
|
||||
for (struct ifaddrs *cur = ifaddr; cur != NULL; cur = cur->ifa_next) {
|
||||
struct sockaddr *address = cur->ifa_addr;
|
||||
if (address == nil) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out any interfaces that aren't IPv4.
|
||||
if (address->sa_family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out any interfaces that aren't en0 (Wi-Fi/Ethernet).
|
||||
NSString *interfaceName = @(cur->ifa_name);
|
||||
if (![interfaceName isEqualToString:@"en0"]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t host = ((struct sockaddr_in *)address)->sin_addr.s_addr;
|
||||
result = [GNCIPv4Address addressFromFourByteInt:host];
|
||||
break;
|
||||
}
|
||||
freeifaddrs(ifaddr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// MARK: - Private Methods (Implementation)
|
||||
|
||||
- (BOOL)internalStartListeningWithPSKIdentity:(nullable NSData *)PSKIdentify
|
||||
PSKSharedSecret:(nullable NSData *)PSKSharedSecret
|
||||
includePeerToPeer:(BOOL)includePeerToPeer
|
||||
error:(NSError **_Nullable)error {
|
||||
nw_parameters_t parameters =
|
||||
(PSKIdentify == nil || PSKSharedSecret == nil)
|
||||
? GNCBuildNonTLSParameters(/*includePeerToPeer=*/includePeerToPeer)
|
||||
: GNCBuildTLSParameters(/*PSK=*/PSKSharedSecret, /*identity=*/PSKIdentify,
|
||||
/*includePeerToPeer=*/includePeerToPeer);
|
||||
if (!parameters) {
|
||||
GTMLoggerError(@"[GNCNWFrameworkServerSocket] Failed to create NW parameters.");
|
||||
return NO;
|
||||
}
|
||||
|
||||
// If the server socket port is zero, a random port will be selected. The server socket port
|
||||
// will be updated to reflect the port it's listening on, once the listener transitions to the
|
||||
// ready state.
|
||||
if (self.port == 0) {
|
||||
_listener = nw_listener_create(parameters);
|
||||
} else {
|
||||
@@ -215,74 +315,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)startAdvertisingServiceName:(NSString *)serviceName
|
||||
serviceType:(NSString *)serviceType
|
||||
txtRecords:(NSDictionary<NSString *, NSString *> *)txtRecords {
|
||||
GTMLoggerInfo(@"[GNCNWFrameworkServerSocket] Start advertising {serviceName:%@, "
|
||||
@"serviceType: %@}",
|
||||
serviceName, serviceType);
|
||||
|
||||
nw_advertise_descriptor_t advertiseDescriptor = nw_advertise_descriptor_create_bonjour_service(
|
||||
[serviceName UTF8String], [serviceType UTF8String], /*domain=*/nil);
|
||||
nw_txt_record_t txtRecord = nw_txt_record_create_dictionary();
|
||||
for (NSString *key in txtRecords) {
|
||||
NSString *recordValue = [txtRecords objectForKey:key];
|
||||
nw_txt_record_set_key(txtRecord, [key UTF8String], [recordValue UTF8String],
|
||||
[recordValue length]);
|
||||
GTMLoggerDebug(@"[GNCNWFrameworkServerSocket] Text record {key: "
|
||||
@"%@, value: %@}",
|
||||
key, recordValue);
|
||||
}
|
||||
nw_advertise_descriptor_set_txt_record_object(advertiseDescriptor, txtRecord);
|
||||
nw_listener_set_advertise_descriptor(_listener, advertiseDescriptor);
|
||||
}
|
||||
|
||||
- (void)stopAdvertising {
|
||||
nw_listener_set_advertise_descriptor(_listener, nil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attemps to find an IPv4 hostname for a Wi-Fi/Ethernet interface.
|
||||
*
|
||||
* Returns the IP address as a 4 byte string. If not available, this returns an empty string to
|
||||
* align with the Windows implementation.
|
||||
*/
|
||||
+ (GNCIPv4Address *)lookupIpAddress {
|
||||
struct ifaddrs *ifaddr;
|
||||
|
||||
// Note: The data returned by `getifaddrs()` is dynamically allocated and should be freed using
|
||||
// `freeifaddrs()` when no longer needed.
|
||||
//
|
||||
// See: https://linux.die.net/man/3/getifaddrs
|
||||
if (getifaddrs(&ifaddr) == -1) {
|
||||
return [GNCIPv4Address addressFromFourByteInt:0];
|
||||
}
|
||||
|
||||
// Walk through linked list, maintaining head pointer so we can free list later.
|
||||
for (struct ifaddrs *cur = ifaddr; cur != nil; cur = cur->ifa_next) {
|
||||
struct sockaddr *address = cur->ifa_addr;
|
||||
if (address == nil) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out any interfaces that aren't IPv4.
|
||||
if (address->sa_family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out any interfaces that aren't en0 (Wi-Fi/Ethernet).
|
||||
NSString *interfaceName = @(cur->ifa_name);
|
||||
if (![interfaceName isEqualToString:@"en0"]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t host = ((struct sockaddr_in *)address)->sin_addr.s_addr;
|
||||
freeifaddrs(ifaddr);
|
||||
return [GNCIPv4Address addressFromFourByteInt:host];
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return [GNCIPv4Address addressFromFourByteInt:0];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
Reference in New Issue
Block a user