Add initial implementation for Wi-Fi LAN medium that use the Network framework

PiperOrigin-RevId: 508784614
This commit is contained in:
Nick Bourdakos
2023-02-10 16:47:27 -08:00
committed by Copybara-Service
parent 1d01973d17
commit 60d021b5f2
5 changed files with 134 additions and 7 deletions
@@ -29,6 +29,7 @@ objc_library(
"WifiLan/GNCMBonjourService.m",
"WifiLan/GNCMBonjourUtils.m",
"WifiLanV2/GNCWiFiLANError.m",
"WifiLanV2/GNCWiFiLANMedium.m",
"WifiLanV2/GNCWiFiLANServerSocket.m",
"WifiLanV2/GNCWiFiLANServerSocket+Internal.h",
"WifiLanV2/GNCWiFiLANSocket.m",
@@ -45,6 +46,7 @@ objc_library(
"WifiLan/GNCMBonjourService.h",
"WifiLan/GNCMBonjourUtils.h",
"WifiLanV2/GNCWiFiLANError.h",
"WifiLanV2/GNCWiFiLANMedium.h",
"WifiLanV2/GNCWiFiLANServerSocket.h",
"WifiLanV2/GNCWiFiLANSocket.h",
],
@@ -0,0 +1,64 @@
// Copyright 2023 Google LLC
//
// 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
//
// https://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 <Foundation/Foundation.h>
@class GNCWiFiLANServerSocket;
/**
* The @c GNCWiFiLANMedium object is used as a delegate by the platform abstraction layer for
* Wi-Fi LAN related functionality on Apple platforms.
*/
@interface GNCWiFiLANMedium : NSObject
/**
* Listens for incoming connections 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[out] error Error that will be populated on failure.
* @return Returns a server socket or nil if an error has occured.
*/
- (nullable GNCWiFiLANServerSocket *)listenForServiceOnPort:(NSInteger)port
error:(NSError **_Nullable)error;
/**
* Creates a Bonjour service that advertises the listener on the local network.
*
* @param port The port of the listener to advertise.
* @param serviceName The Bonjour name of the service.
* @param serviceType The Bonjour type of the service.
* @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;
/**
* Removes the Bonjour service advertisement.
*
* @param port The port of the listener to stop advertising.
*/
- (void)stopAdvertisingPort:(NSInteger)port;
@end
@@ -0,0 +1,61 @@
// Copyright 2023 Google LLC
//
// 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
//
// https://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 "internal/platform/implementation/apple/Mediums/WifiLanV2/GNCWiFiLANMedium.h"
#import <Foundation/Foundation.h>
#import "internal/platform/implementation/apple/Mediums/WifiLanV2/GNCWiFiLANServerSocket+Internal.h"
#import "internal/platform/implementation/apple/Mediums/WifiLanV2/GNCWiFiLANServerSocket.h"
#import "GoogleToolboxForMac/GTMLogger.h"
@implementation GNCWiFiLANMedium {
// Usage of .count should be avoided. Zombie keys won't show up in -keyEnumerator, but WILL be
// included in .count until the next time that the internal hashtable is resized.
NSMapTable<NSNumber *, GNCWiFiLANServerSocket *> *_serverSockets;
}
- (instancetype)init {
if (self = [super init]) {
_serverSockets = [NSMapTable strongToWeakObjectsMapTable];
}
return self;
}
- (GNCWiFiLANServerSocket *)listenForServiceOnPort:(NSInteger)port error:(NSError **)error {
GNCWiFiLANServerSocket *serverSocket = [[GNCWiFiLANServerSocket alloc] initWithPort:port];
BOOL success = [serverSocket startListeningWithError:error];
if (success) {
[_serverSockets setObject:serverSocket forKey:@(serverSocket.port)];
return serverSocket;
}
return nil;
}
- (void)startAdvertisingPort:(NSInteger)port
serviceName:(NSString *)serviceName
serviceType:(NSString *)serviceType
txtRecords:(NSDictionary<NSString *, NSString *> *)txtRecords {
GNCWiFiLANServerSocket *serverSocket = [_serverSockets objectForKey:@(port)];
[serverSocket startAdvertisingServiceName:serviceName
serviceType:serviceType
txtRecords:txtRecords];
}
- (void)stopAdvertisingPort:(NSInteger)port {
GNCWiFiLANServerSocket *serverSocket = [_serverSockets objectForKey:@(port)];
[serverSocket stopAdvertising];
}
@end
@@ -28,7 +28,7 @@
*
* @param port The port of the server socket.
*/
- (nonnull instancetype)initWithPort:(nonnull NSNumber *)port NS_DESIGNATED_INITIALIZER;
- (nonnull instancetype)initWithPort:(NSInteger)port NS_DESIGNATED_INITIALIZER;
/**
* The 4 byte binary representation for the IPv4 address of the physical network interface.
@@ -38,7 +38,7 @@
/**
* The port of the server socket.
*/
@property(nonatomic, readonly, copy) NSNumber *port;
@property(nonatomic, readonly) NSInteger port;
/**
* Returns an arbitrary, connected socket, ready to exchange data.
@@ -41,10 +41,10 @@
NSError *_listenerError;
}
- (instancetype)initWithPort:(NSNumber *)port {
- (instancetype)initWithPort:(NSInteger)port {
self = [super init];
if (self) {
_port = [port copy];
_port = port;
_condition = [[NSCondition alloc] init];
_listenerState = nw_listener_state_invalid;
}
@@ -117,10 +117,10 @@
// 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 intValue] == 0) {
if (self.port == 0) {
_listener = nw_listener_create(parameters);
} else {
_listener = nw_listener_create_with_port([[self.port stringValue] UTF8String], parameters);
_listener = nw_listener_create_with_port([[@(self.port) stringValue] UTF8String], parameters);
}
// Register to listen for incoming connections.
@@ -202,7 +202,7 @@
[self close];
return NO;
case nw_listener_state_ready:
_port = @(nw_listener_get_port(_listener));
_port = nw_listener_get_port(_listener);
return YES;
}
}