blob: 5dd7dbac973ac00375c2ad61059d575cca4666bb [file] [log] [blame]
Chris Simpsona9b6c702018-04-08 07:11:37 -04001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20import Foundation
21import CoreFoundation
22
Antoine Cœur08a6eb62019-07-08 18:42:09 +080023#if !swift(>=4.2)
24// Swift 3/4 compatibility
25fileprivate extension RunLoopMode {
26 static let `default` = defaultRunLoopMode
27}
28#endif
29
Chris Simpsona9b6c702018-04-08 07:11:37 -040030#if os(Linux)
31 /// Currently unavailable in Linux
32 /// Remove comments and build to fix
33 /// Currently kConstants for CFSockets don't exist in linux and not all have been moved
34 /// to property structs yet
35#else
36 // Must inherit NSObject for NSStreamDelegate conformance
37 public class TStreamTransport : NSObject, TTransport {
38 public var input: InputStream? = nil
39 public var output: OutputStream? = nil
40
41 public init(inputStream: InputStream?, outputStream: OutputStream?) {
42 input = inputStream
43 output = outputStream
44 }
45
46 public convenience init(inputStream: InputStream?) {
47 self.init(inputStream: inputStream, outputStream: nil)
48 }
49
50 public convenience init(outputStream: OutputStream?) {
51 self.init(inputStream: nil, outputStream: outputStream)
52 }
53
54 deinit {
55 close()
56 }
57
58 public func readAll(size: Int) throws -> Data {
59 guard let input = input else {
60 throw TTransportError(error: .unknown)
61 }
62
63 var read = Data()
64 while read.count < size {
65 var buffer = Array<UInt8>(repeating: 0, count: size - read.count)
66
67 let bytesRead = buffer.withUnsafeMutableBufferPointer { bufferPtr in
68 return input.read(bufferPtr.baseAddress!, maxLength: size - read.count)
69 }
70
71 if bytesRead <= 0 {
72 throw TTransportError(error: .notOpen)
73 }
Antoine Cœur08a6eb62019-07-08 18:42:09 +080074 read.append(Data(buffer))
Chris Simpsona9b6c702018-04-08 07:11:37 -040075 }
76 return read
77 }
78
79 public func read(size: Int) throws -> Data {
80 guard let input = input else {
81 throw TTransportError(error: .unknown)
82 }
83
84 var read = Data()
85 while read.count < size {
86 var buffer = Array<UInt8>(repeating: 0, count: size - read.count)
87 let bytesRead = buffer.withUnsafeMutableBufferPointer {
88 input.read($0.baseAddress!, maxLength: size - read.count)
89 }
90
91 if bytesRead <= 0 {
92 break
93 }
94
Antoine Cœur08a6eb62019-07-08 18:42:09 +080095 read.append(Data(buffer))
Chris Simpsona9b6c702018-04-08 07:11:37 -040096 }
97 return read
98 }
99
100 public func write(data: Data) throws {
101 guard let output = output else {
102 throw TTransportError(error: .unknown)
103 }
104
105 var bytesWritten = 0
106 while bytesWritten < data.count {
Alexander Edgeb4711a62020-04-24 14:43:03 +0100107 bytesWritten = data.withUnsafeBytes { output.write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count) }
Chris Simpsona9b6c702018-04-08 07:11:37 -0400108 if bytesWritten == -1 {
109 throw TTransportError(error: .notOpen)
110 } else if bytesWritten == 0 {
111 throw TTransportError(error: .endOfFile)
112 }
113 }
114 }
115
116
117 public func flush() throws {
118 return
119 }
120
121 public func close() {
122
123 if input != nil {
124 // Close and reset inputstream
125 if let cf: CFReadStream = input {
126 CFReadStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue)
127 }
128
129 input?.delegate = nil
130 input?.close()
Antoine Cœur08a6eb62019-07-08 18:42:09 +0800131 input?.remove(from: .current, forMode: .default)
Chris Simpsona9b6c702018-04-08 07:11:37 -0400132 input = nil
133 }
134
135 if output != nil {
136 // Close and reset output stream
137 if let cf: CFWriteStream = output {
138 CFWriteStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue)
139 }
140 output?.delegate = nil
141 output?.close()
Antoine Cœur08a6eb62019-07-08 18:42:09 +0800142 output?.remove(from: .current, forMode: .default)
Chris Simpsona9b6c702018-04-08 07:11:37 -0400143 output = nil
144 }
145 }
146 }
147#endif