.
.
.
private func publishService() {
// Initialize GCDAsyncSocket
self.socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue());
// Start listening for incoming connections
var error: NSError?;
if (self.socket.acceptOnPort(0, error: &error)) {
// Initialize Service
self.service = NSNetService(domain: "local.", type: "_mpstest._tcp", name: "", port:Int32(self.socket.localPort));
// Configure Service
self.service.delegate = self;
self.service.includesPeerToPeer = true;
self.service.publish();
} else {
println("Unable to create socket. Error \(error?.description) with user info \(error?.userInfo)");
}
}
// MARK: Send Methods
func sendPacket(packet: MPSocketPacket) {
// Encode packet data
var packetData = NSMutableData();
let archiver = NSKeyedArchiver(forWritingWithMutableData: packetData);
archiver.encodeObject(packet, forKey: "packet");
archiver.finishEncoding();
// Initialize Buffer
var buffer = NSMutableData();
// Fill Buffer
var headerLength: UInt64 = UInt64(packetData.length);
buffer.appendBytes(&headerLength, length: sizeof(UInt64));
buffer.appendBytes(packetData.bytes, length: packetData.length);
// Write Buffer
self.socket.writeData(buffer, withTimeout: -1.0, tag: 0);
}
// MARK: NSNetServiceDelegate Methods
func netServiceDidPublish(sender: NSNetService) {
println("Bonjour Service published: domainName= \(sender.domain), type= \(sender.type), name= \(sender.name), onPort= \(sender.port)");
}
func netService(sender: NSNetService, didNotPublish errorDict: [NSObject : AnyObject]) {
println("Failed to publish service: domainName= \(sender.domain), type= \(sender.type), name= \(sender.name), onPort= \(sender.port) error= \(errorDict)");
}
func netServiceDidStop(sender: NSNetService) {
println("Bonjour Service stopped: domainName= \(sender.domain), type= \(sender.type), name= \(sender.name), onPort= \(sender.port)");
}
// MARK: GCDAsyncSocketDelegate method
func socket(sock: GCDAsyncSocket!, didAcceptNewSocket newSocket: GCDAsyncSocket!) {
println("Accepts new socket with host:\(newSocket.connectedHost) and port:\(newSocket.connectedPort))");
// Read data from socket
let size = sizeof(UInt64);
newSocket.readDataToLength(UInt(size), withTimeout: -1.0, tag: 0);
dispatch_async(dispatch_get_main_queue(), {
self.connectedSockets.append(newSocket);
println("Connected sockets are \(self.connectedSockets)");
});
// Create Packet
let message = "Testing Proof of concept";
let packet = MPSocketPacket(packetData: message, packetType: .Unknown, packetAction: .Unknown);
self.sendPacket(packet, toPeers: [newSocket]);
}
func socketDidDisconnect(sock: GCDAsyncSocket!, withError err: NSError!) {
// println("Socket with host:\(sock.connectedHost) and port:\(sock.connectedPort) is disconnected");
if (sock != nil) {
for (index, socket) in enumerate(self.connectedSockets) {
if (socket == sock) {
socket.delegate = nil;
self.connectedSockets.removeAtIndex(index);
}
}
} else {
println("Nil socket is returned");
println("Socket is connected: \(self.socket.isConnected) to address: \(self.socket.connectedHost)");
}
}
deinit {
self.stopPublishing();
}
.
.
.Bonjour Service published: domainName= local., type= _mpstest._tcp., name= iPad 29, onPort= 56256
Accepts new socket with host:169.254.83.213 and port:52838)
Connected sockets are [<GCDAsyncSocket: 0x1763f950>]
.
.
.
private func resolveServiceAddresses() {
self.advertiserService.delegate = self;
self.advertiserService.resolveWithTimeout(30.0);
}
private func connectWithService(service: NSNetService, hostname: String) ->Bool {
var isConnecting:Bool = false;
if (self.browserSocket == nil || !(self.browserSocket?.isConnected)!) {
// Initialize Socket
self.browserSocket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue());
// Connect
while (!isConnecting){
var error: NSError?;
println("Connecting port : \(service.port) and hostname: \(hostname)");
if (self.browserSocket.connectToHost(hostname, onPort: UInt16(service.port), error: &error)) {
isConnecting = true;
} else if (error != nil) {
println("Unable to connect to address. Error \(error) with user info \(error?.userInfo)");
}
}
} else {
println("Connecting is: \(self.browserSocket.isConnected)");
isConnecting = self.browserSocket.isConnected;
}
return isConnecting;
}
private func parseHeader(data: NSData) -> UInt64 {
var headerLength: UInt64 = 0;
memcpy(&headerLength, data.bytes, UInt(sizeof(UInt64)));
return headerLength;
}
private func parseBody(data: NSData) {
let unarchiver = NSKeyedUnarchiver(forReadingWithData: data);
let packet = unarchiver.decodeObjectForKey("packet") as MPSocketPacket;
unarchiver.finishDecoding();
println("Packet Data : \(packet.data)");
println("Packet Type : \(packet.type)");
println("Packet Action : \(packet.action)");
}
// MARK: NSNetServiceBrowserDelegate methods
func netServiceBrowser(aNetServiceBrowser: NSNetServiceBrowser, didFindService aNetService: NSNetService, moreComing: Bool) {
// This device is not advertising/publishing. So don't need any test before updating servies
self.advertiserService = aNetService;
if (!moreComing) {
println("Service found is : \(aNetService)");
self.resolveServiceAddresses();
}
}
func netServiceBrowser(aNetServiceBrowser: NSNetServiceBrowser, didRemoveService aNetService: NSNetService, moreComing: Bool) {
// Update Services which have stopped
self.advertiserService.delegate = nil;
self.advertiserService = nil;
if (!moreComing) {
println("Service left after removing are : \(self.advertiserService?)");
}
}
// MARK: NSNetServiceDelegate methods
func netService(sender: NSNetService, didNotResolve errorDict: [NSObject : AnyObject]) {
sender.delegate = nil;
println("Did not resolve service: domain:\(sender.domain) type:\(sender.type) name:\(sender.name) on port: \(sender.port) with error: \(errorDict)");
}
func netServiceDidResolveAddress(sender: NSNetService) {
// Connect with Service
if (self.connectWithService(sender, hostname: sender.hostName!)) {
println("Connected with service: domainName= \(sender.domain), type= \(sender.type), name= \(sender.name), onPort= \(sender.port) and hostname: \(sender.hostName!)");
} else {
println("Unable to connect with service: domainName= \(sender.domain), type= \(sender.type), name= \(sender.name), onPort= \(sender.port)");
}
}
// GCDAsyncSocketDelegate methods
func socket(sock: GCDAsyncSocket!, didConnectToHost host: String!, port: UInt16) {
println("Socket: \(sock) Did connect to host: \(host) on port:\(port)");
// Start Reading
sock.readDataToLength(UInt(sizeof(UInt64)), withTimeout: -1.0, tag: 0);
}
func socketDidDisconnect(sock: GCDAsyncSocket!, withError err: NSError!) {
println("Socket \(sock) did disconnect with error \(err?)");
}
func socket(sock: GCDAsyncSocket!, didReadData data: NSData!, withTag tag: Int) {
if (tag == 0) {
let bodyLength: UInt64 = self.parseHeader(data);
sock.readDataToLength(UInt(bodyLength), withTimeout: 30.0, tag: 1);
} else if (tag == 1) {
self.parseBody(data);
sock.readDataToLength(UInt(sizeof(UInt64)), withTimeout: -1.0, tag: 0);
}
}
.
.
.
Service found is : <NSNetService 0x17e6df50> local. _mpstest._tcp. iPad 29
Connecting port : 56212 and hostname: iPad-29.local.
Connected with service: domainName= local., type= _mpstest._tcp., name= iPad 29, onPort= 56212 and hostname: iPad-29.local.
is it main thread true
Service left after removing are : nil
Service found is : <NSNetService 0x17e526d0> local. _mpstest._tcp. iPad 29
Connecting port : 56212 and hostname: iPad-29.local.
Connected with service: domainName= local., type= _mpstest._tcp., name= iPad 29, onPort= 56212 and hostname: iPad-29.local.
Socket nil did disconnect with error nil
Socket: <GCDAsyncSocket: 0x17e7f690> Did connect to host: 169.254.140.21 on port:56212
Packet Data : Testing Proof of concept
Packet Type : (Enum Value)
Packet Action : (Enum Value)
Service found is : <NSNetService 0x16d9e860> local. _mpstest._tcp. iPad 29
Connecting port : 56212 and hostname: iPad-29.local.
Connected with service: domainName= local., type= _mpstest._tcp., name= iPad 29, onPort= 56212 and hostname: iPad-29.local.
Socket <GCDAsyncSocket: 0x16eaca80> did disconnect with error Optional(Error Domain=NSPOSIXErrorDomain Code=60 "Operation timed out" UserInfo=0x16d9ec30 {NSLocalizedFailureReason=Error in connect() function, NSLocalizedDescription=Operation timed out})
Service found is : <NSNetService 0x15538da0> local. _mpstest._tcp. iPad 29
Connecting port : 56256 and hostname: iPad-29.local.
Connected with service: domainName= local., type= _mpstest._tcp., name= iPad 29, onPort= 56256 and hostname: iPad-29.local.
Socket <GCDAsyncSocket: 0x1565df50> did disconnect with error Optional(Error Domain=kCFStreamErrorDomainNetDB Code=8 "nodename nor servname provided, or not known" UserInfo=0x1564cee0 {NSLocalizedDescription=nodename nor servname provided, or not known})