Skip to content

Commit f4be0c5

Browse files
committed
Use POSIX functions to build Input/Output streams
1 parent 1c0ba8d commit f4be0c5

File tree

2 files changed

+73
-41
lines changed

2 files changed

+73
-41
lines changed

Sources/NetServiceListener.swift

+2-7
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,8 @@ extension DNSSDNetService {
4545
let this = Unmanaged<DNSSDNetService>.fromOpaque(info).takeRetainedValue()
4646
guard let delegate = this.delegate else { return }
4747
guard let socket = data?.assumingMemoryBound(to: CFSocketNativeHandle.self).pointee else { return }
48-
var readStream: Unmanaged<CFReadStream>?
49-
var writeStream: Unmanaged<CFWriteStream>?
50-
CFStreamCreatePairWithSocket(kCFAllocatorDefault, socket, &readStream, &writeStream)
51-
guard let r = readStream?.takeRetainedValue(),
52-
let w = writeStream?.takeRetainedValue() else { return }
53-
let inputStream = DNSSDNetServiceInputStream(r)
54-
let outputStream = DNSSDNetServiceOutputStream(w)
48+
let inputStream = DNSSDNetServiceInputStream(socket)
49+
let outputStream = DNSSDNetServiceOutputStream(socket)
5550
delegate.netService(this, didAcceptConnectionWith: inputStream, outputStream: outputStream)
5651
}
5752
let this = Unmanaged.passUnretained(self).toOpaque()

Sources/NetServiceStreams.swift

+71-34
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
// Created by Rene Hexel on 10/12/16.
66
// Copyright © 2016 René Hexel. All rights reserved.
77
//
8-
//#if os(Linux)
9-
108
import CoreFoundation
119
import Foundation
1210

@@ -15,50 +13,98 @@ import Foundation
1513
private func CFStreamPropertyKey(rawValue: CFString) -> CFString {
1614
return rawValue
1715
}
16+
17+
/// Set bind the given socket to the given address and listen for connections
18+
///
19+
/// - Parameters:
20+
/// - s: `CFSocket` to bind
21+
/// - address: IP address to bind to (Data containing a `struct sockaddr*`)
22+
/// - Returns: `0` if successful, an error code otherwise
23+
@discardableResult
24+
func CFSocketSetAddress(_ s: CFSocket, _ address: CFData!) -> CFSocketError {
25+
let len = socklen_t(CFDataGetLength(address))
26+
guard address != nil,
27+
len >= socklen_t(MemoryLayout<sockaddr_in>.size),
28+
CFSocketIsValid(s) else {
29+
return CFSocketError(kCFSocketError)
30+
}
31+
let sock = CFSocketGetNative(s)
32+
return CFDataGetBytePtr(address).withMemoryRebound(to: sockaddr.self, capacity: 1) { (addr: UnsafePointer<sockaddr>!) -> CFSocketError in
33+
guard addr != nil else { return CFSocketError(kCFSocketError) }
34+
guard bind(sock, addr, len) == 0,
35+
listen(sock, 256) == 0 else { return CFSocketError(errno) }
36+
return CFSocketError(kCFSocketSuccess)
37+
}
38+
}
1839
#else
1940
private let utf8 = CFStringBuiltInEncodings.UTF8.rawValue
2041
#endif
2142

43+
extension CFSocketNativeHandle {
44+
func get(_ buffer: UnsafeMutableRawPointer, maxLength len: Int) -> Int {
45+
return Int(read(Int32(self), buffer, ssize_t(len)))
46+
}
47+
48+
func put(_ buffer: UnsafeRawPointer, maxLength len: Int) -> Int {
49+
return Int(write(Int32(self), buffer, ssize_t(len)))
50+
}
51+
52+
func closeReadingEnd() {
53+
shutdown(Int32(self), Int32(SHUT_RD))
54+
}
55+
56+
func closeWritingEnd() {
57+
shutdown(Int32(self), Int32(SHUT_WR))
58+
}
59+
60+
func has(events: Int16 = Int16(POLLIN)) -> Bool {
61+
var fd = pollfd(fd: Int32(self), events: events, revents: 0)
62+
return poll(&fd, 1, 0) > 0
63+
}
64+
}
65+
2266
public class DNSSDNetServiceInputStream: InputStream {
23-
var cfStream: CFReadStream
67+
var sock: CFSocketNativeHandle
68+
var status = Status.open
2469

25-
/// Initialise from a `CFReadStream`
70+
/// Initialise from a `CFSocketNativeHandle`
2671
///
27-
/// - Parameter stream: CoreFoundation read stream to initialise from
28-
public init(_ stream: CFReadStream) {
29-
cfStream = stream
72+
/// - Parameter socket: Already connected socket to initialise from
73+
public init(_ socket: CFSocketNativeHandle) {
74+
sock = socket
3075
super.init(data: Data())
3176
}
3277

3378
public override func read(_ buffer: UnsafeMutablePointer<UInt8>, maxLength len: Int) -> Int {
34-
return CFReadStreamRead(cfStream, buffer, CFIndex(len))
79+
return sock.get(buffer, maxLength: len)
3580
}
3681

3782
public override func getBuffer(_ buffer: UnsafeMutablePointer<UnsafeMutablePointer<UInt8>?>, length len: UnsafeMutablePointer<Int>) -> Bool {
3883
return false
3984
}
4085

4186
public override var hasBytesAvailable: Bool {
42-
return CFReadStreamHasBytesAvailable(cfStream)
87+
return sock.has(events: Int16(POLLIN))
4388
}
4489

4590
public override func open() {
46-
CFReadStreamOpen(cfStream)
4791
}
4892

4993
public override func close() {
50-
CFReadStreamClose(cfStream)
94+
sock.closeReadingEnd()
95+
status = Status.closed
5196
}
5297

5398
public override var streamStatus: Status {
54-
let status = CFReadStreamGetStatus(cfStream)
55-
return Stream.Status(rawValue: unsafeBitCast(status, to: UInt.self))!
99+
return status
56100
}
57101
}
58102

59103

60104
public class DNSSDNetServiceOutputStream: OutputStream {
61-
var cfStream: CFWriteStream!
105+
var sock: CFSocketNativeHandle
106+
var status = Status.open
107+
var properties = Dictionary<PropertyKey, PropertyValue>()
62108

63109
#if os(Linux)
64110
public typealias PropertyValue = AnyObject
@@ -70,50 +116,41 @@ public class DNSSDNetServiceOutputStream: OutputStream {
70116
public typealias PropertyValue = Any
71117
#endif
72118

73-
public init(_ stream: CFWriteStream) {
74-
cfStream = stream
119+
public init(_ socket: CFSocketNativeHandle) {
120+
sock = socket
75121
super.init(toMemory: ())
76122
}
77123

78124

79125
// writes the bytes from the specified buffer to the stream up to len bytes. Returns the number of bytes actually written.
80126
public override func write(_ buffer: UnsafePointer<UInt8>, maxLength len: Int) -> Int {
81-
return CFWriteStreamWrite(cfStream, buffer, len)
127+
return sock.put(buffer, maxLength: len)
82128
}
83129

84130
// returns YES if the stream can be written to or if it is impossible to tell without actually doing the write.
85131
public override var hasSpaceAvailable: Bool {
86-
return CFWriteStreamCanAcceptBytes(cfStream)
132+
return sock.has(events: Int16(POLLOUT))
87133
}
88134

89135
public override func open() {
90-
CFWriteStreamOpen(cfStream)
91136
}
92137

93138
public override func close() {
94-
CFWriteStreamClose(cfStream)
139+
sock.closeReadingEnd()
140+
status = Status.closed
95141
}
96142

97143
public override var streamStatus: Status {
98-
let status = CFWriteStreamGetStatus(cfStream)
99-
return Stream.Status(rawValue: unsafeBitCast(status, to: UInt.self))!
144+
return status
100145
}
101146

102147
public override func property(forKey key: PropertyKey) -> PropertyValue? {
103-
return key.rawValue.withCString {
104-
guard let k = CFStringCreateWithCString(kCFAllocatorDefault, $0, utf8) else {
105-
return nil
106-
}
107-
return CFWriteStreamCopyProperty(cfStream, CFStreamPropertyKey(rawValue: k))
108-
}
148+
return properties[key]
109149
}
110150

111151
public override func setProperty(_ property: PropertyValue?, forKey key: PropertyKey) -> Bool {
112-
return key.rawValue.withCString {
113-
guard let k = CFStringCreateWithCString(kCFAllocatorDefault, $0, utf8) else {
114-
return false
115-
}
116-
return CFWriteStreamSetProperty(cfStream, CFStreamPropertyKey(rawValue: k), property as AnyObject?)
117-
}
152+
let rv = super.setProperty(property, forKey: key)
153+
properties[key] = property
154+
return rv
118155
}
119156
}

0 commit comments

Comments
 (0)