diff options
| author | Dustin Mierau <dustin@mierau.me> | 2024-01-13 19:12:12 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2024-01-13 19:12:12 -0800 |
| commit | 3f4e2c33a4c2719388d9378def981688fcaed210 (patch) | |
| tree | 01928a9347ca2dc18478da4107365a968637ccf5 /Hotline/Shared/NetSocket.swift | |
| parent | 2f210991684c87073dd7534d2d0416d91cf50275 (diff) | |
Rewrite HotlineClient to use new simpler NetSocket stream based socket lib. Seems to be working well and has fixed some connection issues with certain servers. This does away with Apple's NWConnection for everything but file transfers which I still want to be processing on another thread so will keep NWConnection for now.
Diffstat (limited to 'Hotline/Shared/NetSocket.swift')
| -rw-r--r-- | Hotline/Shared/NetSocket.swift | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/Hotline/Shared/NetSocket.swift b/Hotline/Shared/NetSocket.swift index e474f5a..5b33f61 100644 --- a/Hotline/Shared/NetSocket.swift +++ b/Hotline/Shared/NetSocket.swift @@ -41,6 +41,10 @@ final class NetSocket: NSObject, StreamDelegate { private var status: NetSocketStatus = .disconnected + @MainActor public func has(_ length: Int) -> Bool { + return (self.available >= length) + } + override init() {} @MainActor public func connect(host: String, port: Int) { @@ -59,14 +63,16 @@ final class NetSocket: NSObject, StreamDelegate { inputStream?.delegate = self outputStream?.delegate = self - inputStream?.schedule(in: .current, forMode: .common) - outputStream?.schedule(in: .current, forMode: .common) + inputStream?.schedule(in: .current, forMode: .default) + outputStream?.schedule(in: .current, forMode: .default) inputStream?.open() outputStream?.open() } @MainActor public func close(_ err: Error? = nil) { + print("NetSocket: Closed") + let disconnected = (self.status != .disconnected) self.status = .disconnected @@ -75,8 +81,8 @@ final class NetSocket: NSObject, StreamDelegate { self.output?.delegate = nil self.input?.close() self.output?.close() - self.input?.remove(from: .current, forMode: .common) - self.output?.remove(from: .current, forMode: .common) + self.input?.remove(from: .current, forMode: .default) + self.output?.remove(from: .current, forMode: .default) self.input = nil self.output = nil self.inputBuffer = [] @@ -85,8 +91,6 @@ final class NetSocket: NSObject, StreamDelegate { if disconnected { self.delegate?.netsocketDisconnected(socket: self, error: err) } - - print("NetSocket: Closed") } @MainActor public func write(_ data: Data) { @@ -166,6 +170,7 @@ final class NetSocket: NSObject, StreamDelegate { } let bytesWritten = output.write(self.outputBuffer, maxLength: self.outputBuffer.count) + print("NetSocket => \(bytesWritten) bytes") if bytesWritten > 0 { self.outputBuffer.removeFirst(bytesWritten) self.delegate?.netsocketSent(socket: self, count: bytesWritten) @@ -180,9 +185,10 @@ final class NetSocket: NSObject, StreamDelegate { return } - let bytesRead = input.read(&self.readBuffer, maxLength: self.readBuffer.capacity) + let bytesRead = input.read(&self.readBuffer, maxLength: 4 * 1024) + print("NetSocket <= \(bytesRead) bytes") if bytesRead > 0 { - self.inputBuffer.append(contentsOf: readBuffer[0..<bytesRead]) + self.inputBuffer.append(contentsOf: self.readBuffer[0..<bytesRead]) self.delegate?.netsocketReceived(socket: self, bytes: self.inputBuffer) } else if bytesRead == -1 { @@ -199,6 +205,9 @@ final class NetSocket: NSObject, StreamDelegate { switch eventCode { case .openCompleted: + if aStream == input { + self.setupStreamOptions() + } if input.streamStatus == .open && output.streamStatus == .open { if self.status == .connecting { print("NetSocket: Connected") @@ -224,4 +233,37 @@ final class NetSocket: NSObject, StreamDelegate { break } } + + // MARK: - + + private func setupStreamOptions() { + if let input = self.input { + let socketData: Data = CFReadStreamCopyProperty(input as CFReadStream, CFStreamPropertyKey.socketNativeHandle) as! Data; + var socketHandle: CFSocketNativeHandle = 0; + (socketData as NSData).getBytes(&socketHandle, length: MemoryLayout.size(ofValue: socketHandle)); + + var value: Int = 0; + let size = UInt32(MemoryLayout.size(ofValue: value)); + + value = 1; + if setsockopt(socketHandle, IPPROTO_TCP, TCP_NODELAY, &value, size) != 0 { + print("NetSocket: failed to set TCP_NODELAY"); + } + // Enable keepalive + value = 1; + if setsockopt(socketHandle, SOL_SOCKET, SO_KEEPALIVE, &value, size) != 0 { + print("NetSocket: failed to set SO_KEEPALIVE"); + } + // Number of keepalives before close (including first keepalive packet) + value = 5 + if setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPCNT, &value, size) != 0 { + print("NetSocket: failed to set TCP_KEEPCNT"); + } + // Idle time used when SO_KEEPALIVE is enabled. Sets how long connection must be idle before keepalive is sent. + value = 60 + if setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPALIVE, &value, size) != 0 { + print("NetSocket: failed to set TCP_KEEPALIVE") + } + } + } } |