GreeterSender.swift 5.51 KB
Newer Older
1 2
import Foundation
import CocoaAsyncSocket
3
import NetUtils
4 5 6 7 8

extension Greeter
{
    class Sender
    {
9
        @objc class AbstractSender : NSObject, GCDAsyncUdpSocketDelegate
10 11 12
        {
            var socket:GCDAsyncUdpSocket? = nil
            var port:UInt16
13
            var interface:Interface!
14
            var deviceId:DeviceId!
15
            var address:String!
16
            var announcementInterval:NSTimeInterval
17
            var timer : NSTimer? = nil
18 19 20 21 22 23 24 25 26 27 28 29 30
            
            var isStarted: Bool { get { return self.timer != nil && self.timer!.valid } }
            
            var addresses : [Announcement.Device.Address] = [] {
                didSet {
                    do {
                        if isStarted {
                            try sendAnnouncement()
                        }
                    }
                    catch {}
                }
            }
31

32
            init(address:String, port:UInt16, interface:Interface, deviceId:DeviceId, socket:GCDAsyncUdpSocket? = nil, announcementInterval:NSTimeInterval = Greeter.defaultAnnouncementInterval) throws
33 34 35 36 37
            {
                self.address = address
                self.port = port
                self.interface = interface
                self.deviceId = deviceId
38
                self.announcementInterval = announcementInterval
39
                super.init()
40 41 42 43 44 45
                if let s = socket {
                    try self.setSocket(s)
                }
                else {
                    try self.setSocket(GCDAsyncUdpSocket())
                }
46 47
            }
            
48 49 50 51 52 53
            func start() throws
            {
                try sendAnnouncement()
                startTimer()
            }
            
54 55 56 57 58 59 60 61 62 63 64 65
            func stop()
            {
                if let t = self.timer {
                    t.invalidate()
                    self.timer = nil
                }
                if let s = self.socket {
                    s.close()
                    self.socket = nil
                }
            }
            
66 67
            func startTimer()
            {
68
                self.timer = NSTimer.scheduledTimerWithTimeInterval(announcementInterval, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
69 70 71 72 73 74 75 76 77
            }
            
            func timerFired() {
                do {
                    try sendAnnouncement()
                }
                catch let sendError {
                    print("[Greeter] Sending announcement failed for interface \(self.interface): \(sendError)")
                }
78 79 80 81 82 83 84 85
            }
            
            func setSocket(s:GCDAsyncUdpSocket) throws
            {
                self.socket = s
                self.socket?.synchronouslySetDelegate(self)
                self.socket?.synchronouslySetDelegateQueue(dispatch_get_main_queue())
                self.socket?.setIPv4Enabled(false)
86
                self.socket?.setIPv6Enabled(false)
87 88 89 90
            }
            
            func sendAnnouncement() throws
            {
91
                precondition(self.socket != nil, "Socket is not configured properly")
92
                guard self.addresses.count > 0 else { return }
93
                
94
                let a = Announcement(deviceId: self.deviceId, addresses:self.addresses)
95 96 97 98 99 100 101
                let writer = XdrWriter()
                writer.write(a)
                let data = NSData(bytes: writer.xdrBytes, length: writer.xdrBytes.count)
                self.socket!.sendData(data, toHost: self.address, port: self.port, withTimeout: Greeter.sendTimeout, tag: 0)
            }
        }
        
102
        class IPv6 : AbstractSender
103
        {
104
            override func setSocket(s:GCDAsyncUdpSocket) throws
105
            {
106 107
                try super.setSocket(s)
                self.socket?.setIPv6Enabled(true)
108 109
                try self.socket?.bindToPort(0, interface: self.interface.name)
                self.socket?.setIpv6Multicast(self.interface.name)
110
            }
111 112 113 114
        }
        
        class IPv4 : AbstractSender
        {
115
            init(port:UInt16, interface:Interface, deviceId:DeviceId, socket:GCDAsyncUdpSocket? = nil, announcementInterval:NSTimeInterval = Greeter.defaultAnnouncementInterval) throws
116
            {
117 118
                precondition(interface.broadcastAddress != nil, "trying to create sender for IPv4 interface that has no broadcast address")
                try super.init(address: interface.broadcastAddress!, port: port, interface: interface, deviceId: deviceId, socket: socket, announcementInterval:announcementInterval)
119 120
            }
            
121
            override func setSocket(s:GCDAsyncUdpSocket) throws
122
            {
123
                try super.setSocket(s)
124
                self.socket?.setIPv4Enabled(true)
125
                try self.socket?.enableBroadcast(true)
126
                try self.socket?.bindToPort(0, interface: self.interface.name)
127 128
            }
        }
129 130 131 132 133 134 135 136 137 138
        
        class Global : AbstractSender {
            init(discoveryServer:String, port: UInt16, interface:Interface, deviceId:DeviceId, socket:GCDAsyncUdpSocket? = nil, announcementInterval:NSTimeInterval = Greeter.defaultGlobalAnnouncementInterval) throws
            {
                try super.init(address: discoveryServer, port: port, interface: interface, deviceId: deviceId, socket:socket, announcementInterval:announcementInterval)
            }
            
            override func setSocket(s: GCDAsyncUdpSocket) throws {
                try super.setSocket(s)
                self.socket?.setIPv4Enabled(true)
139
                try self.socket?.bindToPort(0, interface: self.interface.name)
140 141
            }
        }
142 143
    }
}