Hi everyone,
I'm currently working on a project that involves using the Network framework on macOS 10.15 and iOS 12. While implementing error handling for my network connections, I encountered a warning about the conformance of 'NWError' to 'CustomNSError', which is only available in macOS 13.3 or newer.
Here's the warning message I received while compiling the code:
Warning: conformance of 'NWError' to 'CustomNSError' is only available in macOS 13.3 or newer
self.vConnection = try NWConnection (to: self.vBaseSocketProperties!.uEndpoint!, using: self.vBaseSocketProperties!.uParamters!)
self.vConnection?.stateUpdateHandler = { connectionState in
switch connectionState {
case .failed(let err):
error_code = err.errorCode
//Below all the other cases are also handled.
}
Post
Replies
Boosts
Views
Activity
Hey everyone,
I'm tackling a scenario where I need to fetch a comprehensive list of both IPv4 and IPv6 addresses linked to a particular DNS. I know about the POSIX function getaddrinfo(), but I'm on the lookout for an asynchronous solution. Previously, I could've used CFHost, but unfortunately, it's been deprecated. Any suggestions or insights on how to achieve this asynchronously would be greatly appreciated!
Thanks,
Harshal
Hello,
I've been encountering some challenges while working with NWConnectionGroup and NWMulticastGroup for multicast operations on iOS. I have a few doubts and issues that I would like to address:
1. NWMulticastGroup Initialization
It seems that when initializing NWMulticastGroup, only one NWEndpoint can be passed, and attempting to pass multiple endpoints results in failure. Can someone confirm if this behavior is correct?
2. Interface Level Control
Upon initializing NWConnectionGroup, it appears that packets are received on all interfaces without the ability to control this at the interface level. Is this correct? If not is there a way to configure NWConnectionGroup to receive packets on all interfaces?
3. Sending Behavior
During the send operation, it appears that the data is sent through any one of the available interfaces, and there doesn't seem to be an option to configure it to send through all available endpoints. Is there a way to enable sending data through all available endpoints?
Any insights, guidance, or solutions to these issues would be greatly appreciated. Has anyone else encountered similar problems or found workarounds for these limitations?
Thank you for your assistance and support.
Thanks,
Harshal
Hello Everyone,
I'm working on an app that utilizes the new C++ - Swift interop feature. I have a module called ModuleA that contains multiple Swift classes, and I need to store instances of these classes in a C++ class as a class member(to ensure ARC until the class object is deallocated). However, I want to retain the Swift class objects on the stack without directly allocating heap memory from C++.
Sample Swift Code:
public class SwiftClassA {
public init() {}
public func FuncA() -> Void {
// Perform operations specific to SwiftClassA }
}
public class SwiftClassB {
public init() {}
public func FuncA() -> Void {
// Perform operations specific to SwiftClassB
}
}
// Additional Swift classes (SwiftClassC to SwiftClassN) follow a similar structure.
Sample Cpp Code:
CppClass.hpp
#include "ModuleA-Swift.h" // Include generated Swift headerclass
CppClass {
public:
// Functions and declarationsprivate:
XYZ vClassObject; // Placeholder for Any Swift class object
};
CppClass.cpp
#include "ModuleA-Swift.h" // Include generated Swift headervoid
CppClass::SomeFuncA() noexcept
{
ModuleA::SwiftClassA obj = ModuleA::SwiftClassA::init(); // Initialize SwiftClassA object
vClassObject = obj; // Assign SwiftClassA object to vClassObject
}
void CppClass::SomeFuncB() noexcept {
ModuleA::SwiftClassB obj = ModuleA::SwiftClassB::init(); // Initialize SwiftClassB object
vClassObject = obj; // How do I Assign SwiftClassB object to vClassObject?
}
I'm looking for suggestions on how to efficiently store different types of Swift class objects in my C++ class while maintaining stack-based object retention and proper memory management. Any help or insights would be greatly appreciated.
Thanks,
Harshal
Hello everyone,
I'm encountering an issue with Swift and C++ interoperability when passing a void pointer between Swift and C++ functions. When I pass pMessageBuffer (an UnsafeMutableRawPointer) from Swift to MyCppClass.NFCompletion (a static c++ function), which expects a reference to void pointer, Swift throws an error "Cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'Optional' ".
Here is a sample code to help in better visualization of the usecase.
Cpp Code
class MyCppClass {
public:
static void SendData(void *pMessage, TUInt16 pMessageLength) {
// Assume vSocket is my Swift object held in C++.
vSocket.Send(pMessage, pMessageLength);
}
static void NFCompletion(void * & pBuffer, TInt64 pErrorCode, VPtr pCompletionFunction) {
// Process the buffer.
}
};
Swift Code:
public class MySwiftClass {
var vConnection: NWConnection?
public init() {}
public func Send(_ pMessageBuffer: UnsafeMutableRawPointer, _ pMessageLength: TSUInt16) {
let messageData = Data(bytesNoCopy: pMessageBuffer, count: Int(pMessageLength), deallocator: .none)
self.vConnection?.send(content: messageData, completion: .contentProcessed { nw_error in
var error_code: TSInt64 = 0
if let nw_error = nw_error {
error_code = self.InternalGetNetworkErrorCode(nw_error)
}
// Here's where the issue arises:
MyCppClass.NFCompletion(pMessageBuffer, TInt64(error_code), self.uCompletionHandler)
})
}
// Example function to handle network errors
private func InternalGetNetworkErrorCode(_ error: Error) -> TSInt64 {
// Implementation to convert nw_error to TSInt64 error code
return 0 // Placeholder return value
}
}
Could someone please help me understand why this conversion error occurs? How should I correctly handle passing a void pointer between Swift and C++ functions, ensuring compatibility and proper memory management?
Note: TSInt64 is typealias for swift Int and TInt64 is alias of c++ int_64t.
Thank you in advance for your assistance!
Regards,
Harshal
Hello everyone,
I'm currently developing an application that involves network communication on an Apple Watch.
I'm using Apple's network framework for communication and for validation purpose I need to establish communication between an Apple Watch simulator and an external command-line tool (nc). To send the connection requests, I require the IP address of the Apple Watch simulator.
I've been unable to locate the IP address of the Apple Watch simulator after searching is settings everywhere. This IP address is required for setting up network requests and ensuring effective testing and integration of Apple's network framework.
Could someone please provide guidance on how to obtain the IP address of the Apple Watch simulator? Specifically, I need to know how to retrieve this IP address so that I can configure my external command-line application (nc) to send connection requests to the simulator.
Thank you for your assistance and insights!
Regards,
Harshal.
Hi everyone,
I’m working on an app where I need to separate IPv4 and IPv6 traffic on a specific port, let's say "X", using the Network Framework. However, I’ve run into a problem: it appears that I'm only able to open a single NWListener for a given port number. I was under the impression that I should be able to create distinct IPv4 and IPv6 listeners for the same port "X".
Here’s the sample code I’ve written:
var params: NWParameters
var l1: NWListener
var l2: NWListener
params = NWParameters.udp
let protocolOptions = params.defaultProtocolStack.internetProtocol! as NWProtocolOptions
let ipOptions = protocolOptions as! NWProtocolIP.Options
ipOptions.version = .v6
l1 = try NWListener(using: params, on: NWEndpoint.Port(rawValue: 54192)!)
l1.stateUpdateHandler = InternalListenerStateHandler
l1.newConnectionHandler = InternalNewConnectionHandler
l1.start(queue: .global())
ipOptions.version = .v4
l2 = try NWListener(using: params, on: NWEndpoint.Port(rawValue: 54192)!)
l2.stateUpdateHandler = InternalListenerStateHandler
l2.newConnectionHandler = InternalNewConnectionHandler
l2.start(queue: .global())
I’m trying to figure out why this approach isn’t working. Is there a way to manage both IPv4 and IPv6 traffic on the same port using the Network Framework, or is there something I’m overlooking in my setup?
Additionally, when I switch to the BSD framework, I can successfully open two sockets on the same port by setting the "IPV6_ONLY" property on the IPv6 socket.
Any insights or advice would be greatly appreciated!
Thanks,
Harshal
Hello,
I am using the withUnsafePointer API in Swift and have a question regarding the validity of the pointer returned by this API. Specifically, I want to understand if the pointer remains valid if the CPU performs a context switch due to its time-slicing mechanism while the closure is executing.
Is the pointer returned by withUnsafePointer guaranteed to be valid throughout the entire execution of the closure, even if a CPU context switch occurs as part of time slicing?
Hello Everyone,
I have a use case where I wanted to interpret the "Data" object received as a part of my NWConnection's recv call. I have my interpretation logic in cpp so in swift I extract the pointer to the raw bytes from Data and pass it to cpp as a UnsafeMutableRawPointer.
In cpp it is received as a void * where I typecast it to char * to read data byte by byte before framing a response.
I am able to get the pointer of the bytes by using
// Swift Code
// pContent is the received Data
if let content = pContent, !content.isEmpty {
bytes = content.withUnsafeBytes { rawBufferPointer in
guard let buffer = rawBufferPointer.baseAddress else {
// return with null data.
}
// invoke cpp method to interpret data and trigger response.
}
// Cpp Code
void InterpretResponse (void * pDataPointer, int pDataLength) {
char * data = (char *) pDataPointer;
for (int iterator = 0; iterator < pDataLength; ++iterator )
{
std::cout << data<< std::endl;
data++;
}
}
When I pass this buffer to cpp, I am unable to interpret it properly.
Can someone help me out here?
Thanks :)
Harshal
Hello,
I'm working with the Network framework in Swift and have encountered an issue when attempting to create multiple NWListener instances on the same port. I am specifically trying to set the allowLocalEndpointReuse property on the NWParameters used for both listeners, but it seems that even with this property set, the second listener fails to start.
Here’s a simplified version of my implementation:
import Foundation
import Network
class UDPServer {
private var listener1: NWListener?
private var listener2: NWListener?
private let port: NWEndpoint.Port
init(port: UInt16) {
self.port = NWEndpoint.Port(rawValue: port) ?? NWEndpoint.Port(45000)
startListeners()
}
private func startListeners() {
let udpOptions = NWProtocolUDP.Options()
let params = NWParameters(udp: udpOptions)
params.allowLocalEndpointReuse = true
// Create first listener
do {
listener1 = try NWListener(using: params, on: port)
listener1?.start(queue: .global())
} catch {
print("Failed to create Listener 1: \(error)")
}
// Create second listener
do {
listener2 = try NWListener(using: params, on: port)
listener2?.start(queue: .global())
} catch {
print("Failed to create Listener 2: \(error)")
}
}
}
// Usage example
let udpServer = UDPServer(port: 45000)
RunLoop.main.run()
Observations:
I expect both listeners to operate without issues since I set allowLocalEndpointReuse to true.
However, when I attempt to start the second listener on the same port, it fails with an error.
output
nw_path_evaluator_evaluate NECP_CLIENT_ACTION_ADD error [48: Address already in use]
nw_path_create_evaluator_for_listener nw_path_evaluator_evaluate failed
nw_listener_start_on_queue [L2] nw_path_create_evaluator_for_listener failed
Listener 1 ready on port 45000
Listener 2 failed: POSIXErrorCode(rawValue: 48): Address already in use
Listener 2 cancelled
Questions:
Is there a limitation in the Network framework regarding multiple listeners on the same port even with allowLocalEndpointReuse?
Should I be using separate NWParameters for each listener, or is it acceptable to reuse them?
Even when trying to initialize NWParameters with NWProtocolUDP.Options, it doesn't seem to change anything. What steps should I take to modify these properties effectively?
If I wanted to set the noDelay option for TCP, how would I do that? Even when initializing NWParameters with init(.tls: , .tcp:), it doesn't seem to have any effect.
Any insights or recommendations would be greatly appreciated!
Thank you!
Hello everyone,
I’m currently working on a Swift project using the Network framework to create a multicast-based communication system. Specifically, I’m implementing both a multicast receiver and a sender that join the same multicast group for communication. However, I’ve run into some challenges with the connection management, replying to multicast messages, and handling state updates for both connections and connection groups.
Below is a breakdown of my setup and the specific issues I’ve encountered.
I have two main parts in the implementation: the multicast receiver and the multicast sender. The goal is for the receiver to join the multicast group, receive messages from the sender, and send a reply back to the sender using a direct connection.
Multicast Receiver Code:
import Network
import Foundation
func setupMulticastGroup() -> NWConnectionGroup? {
let multicastEndpoint1 = NWEndpoint.hostPort(host: NWEndpoint.Host("224.0.0.1"), port: NWEndpoint.Port(rawValue: 45000)!)
let multicastParameters = NWParameters.udp
multicastParameters.multipathServiceType = .aggregate
do {
let multicastGroup = try NWMulticastGroup(for: [multicastEndpoint1], from: nil, disableUnicast: false)
let multicastConnections = NWConnectionGroup(with: multicastGroup, using: multicastParameters)
multicastConnections.stateUpdateHandler = InternalConnectionStateUpdateHandler
multicastConnections.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: false, handler: receiveHandler)
multicastConnections.newConnectionHandler = newConnectionHandler
multicastConnections.start(queue: .global())
return multicastConnections
} catch {
return nil
}
}
func receiveHandler(message: NWConnectionGroup.Message, content: Data?, isComplete: Bool) {
print("Received message from \(String(describing: message.remoteEndpoint))")
if let content = content, let messageString = String(data: content, encoding: .utf8) {
print("Received Message: \(messageString)")
}
let remoteEndpoint = message.remoteEndpoint
message.reply(content: "Multicast group on 144 machine ACK from recv handler".data(using: .utf8))
if let connection = multicastConnections?.extract(connectionTo: remoteEndpoint) {
connection.stateUpdateHandler = InternalConnectionRecvStateUpdateHandler
connection.start(queue: .global())
connection.send(content: "Multicast group on 144 machine ACK from recv handler".data(using: .utf8), completion: NWConnection.SendCompletion.contentProcessed({ error in
print("Error code: \(error?.errorCode ?? 0)")
print("Ack sent to \(connection.endpoint)")
}))
}
}
func newConnectionHandler(connection: NWConnection) {
connection.start(queue: .global())
connection.send(content: "Multicast group on 144 machine ACK".data(using: .utf8), completion: NWConnection.SendCompletion.contentProcessed({ error in
print("Error code: \(error?.errorCode ?? 0)")
print("Ack sent to \(connection.endpoint)")
}))
}
func InternalConnectionRecvStateUpdateHandler(_ pState: NWConnection.State) {
switch pState {
case .setup:
NSLog("The connection has been initialized but not started")
case .preparing:
NSLog("The connection is preparing")
case .waiting(let error):
NSLog("The connection is waiting for a network path change. Error: \(error)")
case .ready:
NSLog("The connection is established and ready to send and receive data.")
case .failed(let error):
NSLog("The connection has disconnected or encountered an error. Error: \(error)")
case .cancelled:
NSLog("The connection has been canceled.")
default:
NSLog("Unknown NWConnection.State.")
}
}
func InternalConnectionStateUpdateHandler(_ pState: NWConnectionGroup.State) {
switch pState {
case .setup:
NSLog("The connection has been initialized but not started")
case .waiting(let error):
NSLog("The connection is waiting for a network path change. Error: \(error)")
case .ready:
NSLog("The connection is established and ready to send and receive data.")
case .failed(let error):
NSLog("The connection has disconnected or encountered an error. Error: \(error)")
case .cancelled:
NSLog("The connection has been canceled.")
default:
NSLog("Unknown NWConnection.State.")
}
}
let multicastConnections = setupMulticastGroup()
RunLoop.main.run()
Multicast Sender Code:
import Foundation
import Network
func setupConnection() -> NWConnection {
let params = NWParameters.udp
params.allowLocalEndpointReuse = true
return NWConnection(to: NWEndpoint.hostPort(host: NWEndpoint.Host("224.0.0.1"), port: NWEndpoint.Port(rawValue: 45000)!), using: params)
}
func sendData(using connection: NWConnection, data: Data) {
connection.send(content: data, completion: .contentProcessed { nwError in
if let error = nwError {
print("Failed to send message with error: \(error)")
} else {
print("Message sent successfully")
}
})
}
func setupReceiveHandler(for connection: NWConnection) {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65000) { content, contentContext, isComplete, error in
print("Received data:")
print(content as Any)
print(contentContext as Any)
print(error as Any)
setupReceiveHandler(for: connection)
}
}
let connectionSender = setupConnection()
connectionSender.stateUpdateHandler = internalConnectionStateUpdateHandler
connectionSender.start(queue: .global())
let sendingData = "Hello, this is a multicast message from the process on mac machine 144".data(using: .utf8)!
sendData(using: connectionSender, data: sendingData)
setupReceiveHandler(for: connectionSender)
RunLoop.main.run()
Issues Encountered:
Error Code 0 Even When Connection Refused:
On the receiver side, I encountered this log:
nw_socket_get_input_frames [C1.1.1:1] recvmsg(fd 8, 9216 bytes) [61: Connection refused]
Error code: 0
Ack sent to 10.20.16.144:62707
Questions:
how do I reply to the message if above usage pattern is wrong?
how do I get a NWConnection from the received message to create a separate connection for communication with the sender.
Any insights or suggestions on resolving these issues or improving my multicast communication setup would be greatly appreciated.
Thanks :)