I am building a Swift desktop application that communicates with multiple hardware devices on the network via UDP, using GCDAsyncUDPSocket. For the initial scan, I create a socket and send out a broadcast message and listen for responses. When I get a response from a device, a unique non-broadcast socket is created for that device for all additional communications.
When going through my wired Ethernet, this works almost perfectly. However, when going through WiFi, I see constant ARP requests coming back in Wireshark, many of which are being responded to with the incorrect MAC address for the interface that should be receiving the messages.
I've been looking for two days now trying to find a tried and true solution to the ARP thing without any luck.
I see in the GCDAsync documentation that using sendData toAddress instead of toHost will include the MAC address, but haven't been able to sort out how to create the address NSData object with my interface details to try this, and am not even sure if this will resolve the ARP issue.
Here is my current code for my broadcast socket:
class BroadcastNetworkSocket: NSObject, GCDAsyncUdpSocketDelegate{
var socket:GCDAsyncUdpSocket!
let broadcastIP = "255.255.255.255"
let broadcastPort:UInt16 = 22202
let PORT:UInt16 = 0
override init (){
super.init()
}
init(whichInterface: String){
super.init()
setupConnection(whichInterface)
}
func setupConnection(whichInterface: String){
var error : NSError?
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
socket.setPreferIPv4()
socket.enableBroadcast(true, error: &error)
socket.beginReceiving(&error)
}
func send(message:String, toAddress:String, toPort:UInt16){
let data = message.dataUsingEncoding(NSUTF8StringEncoding)
socket!.sendData(data, toHost: toAddress, port: toPort, withTimeout: 2, tag: 0)
}
func sendNetworkScan(){
let message = "!??#"
let data = message.dataUsingEncoding(NSUTF8StringEncoding)
socket!.sendData(data, toHost: broadcastIP, port: broadcastPort, withTimeout: 2, tag: 0)
println("outgoing message: \(message)");
}
func closeSocket(){
socket!.close()
}
func udpSocket(sock: GCDAsyncUdpSocket!, didReceiveData data: NSData!, fromAddress address: NSData!, withFilterContext filterContext: AnyObject!) {
let theMessage = NSString(data: data, encoding: NSUTF8StringEncoding)
var host: NSString?
var port1: UInt16 = 0
GCDAsyncUdpSocket.getHost(&host, port: &port1, fromAddress: address)
println("incoming message: \(theMessage!)")
println("incoming address: \(host!)")
NSNotificationCenter.defaultCenter().postNotificationName(broadcastNetworkMessageReceivedNotificationKey, object: self, userInfo: ["message":theMessage!, "incomingIP":host!])
}
func verifyIPAddress(incomingText: String)-> Bool{
let validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
if incomingText.rangeOfString(validIpAddressRegex, options: .RegularExpressionSearch) != nil{
return true
}
else {
return false
}
}
}