secretive/Sources/Packages/Sources/SecretAgentKit/SocketController.swift

68 lines
2.7 KiB
Swift
Raw Normal View History

2020-03-04 07:14:38 +00:00
import Foundation
import OSLog
public class SocketController {
2020-03-04 07:14:38 +00:00
2020-05-16 06:19:00 +00:00
private var fileHandle: FileHandle?
private var port: SocketPort?
2020-03-24 06:22:22 +00:00
public var handler: ((FileHandleReader, FileHandleWriter) -> Void)?
2020-03-04 07:14:38 +00:00
public init(path: String) {
Logger().debug("Socket controller setting up at \(path)")
2020-03-04 07:14:38 +00:00
if let _ = try? FileManager.default.removeItem(atPath: path) {
Logger().debug("Socket controller removed existing socket")
2020-03-04 07:14:38 +00:00
}
let exists = FileManager.default.fileExists(atPath: path)
assert(!exists)
Logger().debug("Socket controller path is clear")
2020-03-04 07:14:38 +00:00
port = socketPort(at: path)
configureSocket(at: path)
Logger().debug("Socket listening at \(path)")
2020-03-04 07:14:38 +00:00
}
func configureSocket(at path: String) {
guard let port = port else { return }
fileHandle = FileHandle(fileDescriptor: port.socket, closeOnDealloc: true)
NotificationCenter.default.addObserver(self, selector: #selector(handleConnectionAccept(notification:)), name: .NSFileHandleConnectionAccepted, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleConnectionDataAvailable(notification:)), name: .NSFileHandleDataAvailable, object: nil)
fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!])
}
func socketPort(at path: String) -> SocketPort {
var addr = sockaddr_un()
addr.sun_family = sa_family_t(AF_UNIX)
var len: Int = 0
2020-09-22 06:12:50 +00:00
withUnsafeMutablePointer(to: &addr.sun_path.0) { pointer in
2020-03-04 07:14:38 +00:00
path.withCString { cstring in
len = strlen(cstring)
strncpy(pointer, cstring, len)
}
}
addr.sun_len = UInt8(len+2)
var data: Data!
2020-09-22 06:12:50 +00:00
withUnsafePointer(to: &addr) { pointer in
2020-03-04 07:14:38 +00:00
data = Data(bytes: pointer, count: MemoryLayout<sockaddr_un>.size)
}
return SocketPort(protocolFamily: AF_UNIX, socketType: SOCK_STREAM, protocol: 0, address: data)!
}
@objc func handleConnectionAccept(notification: Notification) {
Logger().debug("Socket controller accepted connection")
2020-03-04 07:14:38 +00:00
guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return }
2020-03-24 06:22:22 +00:00
handler?(new, new)
2020-03-04 07:14:38 +00:00
new.waitForDataInBackgroundAndNotify()
fileHandle?.acceptConnectionInBackgroundAndNotify(forModes: [RunLoop.current.currentMode!])
}
@objc func handleConnectionDataAvailable(notification: Notification) {
Logger().debug("Socket controller has new data available")
2020-03-04 07:14:38 +00:00
guard let new = notification.object as? FileHandle else { return }
Logger().debug("Socket controller received new file handle")
2020-03-24 06:22:22 +00:00
handler?(new, new)
2020-03-04 07:14:38 +00:00
}
}