"Fossies" - the Fresh Open Source Software Archive 
Member "jitsi-meet-7305/ios/app/broadcast-extension/SocketConnection.swift" (26 May 2023, 6077 Bytes) of package /linux/misc/jitsi-meet-7305.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Swift source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * Copyright @ 2021-present 8x8, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 import Foundation
18
19 class SocketConnection: NSObject {
20 var didOpen: (() -> Void)?
21 var didClose: ((Error?) -> Void)?
22 var streamHasSpaceAvailable: (() -> Void)?
23
24 private let filePath: String
25 private var socketHandle: Int32 = -1
26 private var address: sockaddr_un?
27
28 private var inputStream: InputStream?
29 private var outputStream: OutputStream?
30
31 private var networkQueue: DispatchQueue?
32 private var shouldKeepRunning = false
33
34 init?(filePath path: String) {
35 filePath = path
36 socketHandle = Darwin.socket(AF_UNIX, SOCK_STREAM, 0)
37
38 guard socketHandle != -1 else {
39 print("failure: create socket")
40 return nil
41 }
42 }
43
44 func open() -> Bool {
45 print("open socket connection")
46
47 guard FileManager.default.fileExists(atPath: filePath) else {
48 print("failure: socket file missing")
49 return false
50 }
51
52 guard setupAddress() == true else {
53 return false
54 }
55
56 guard connectSocket() == true else {
57 return false
58 }
59
60 setupStreams()
61
62 inputStream?.open()
63 outputStream?.open()
64
65 return true
66 }
67
68 func close() {
69 unscheduleStreams()
70
71 inputStream?.delegate = nil
72 outputStream?.delegate = nil
73
74 inputStream?.close()
75 outputStream?.close()
76
77 inputStream = nil
78 outputStream = nil
79 }
80
81 func writeToStream(buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int {
82 return outputStream?.write(buffer, maxLength: length) ?? 0
83 }
84 }
85
86 extension SocketConnection: StreamDelegate {
87
88 func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
89 switch eventCode {
90 case .openCompleted:
91 print("client stream open completed")
92 if aStream == outputStream {
93 didOpen?()
94 }
95 case .hasBytesAvailable:
96 if aStream == inputStream {
97 var buffer: UInt8 = 0
98 let numberOfBytesRead = inputStream?.read(&buffer, maxLength: 1)
99 if numberOfBytesRead == 0 && aStream.streamStatus == .atEnd {
100 print("server socket closed")
101 close()
102 notifyDidClose(error: nil)
103 }
104 }
105 case .hasSpaceAvailable:
106 if aStream == outputStream {
107 streamHasSpaceAvailable?()
108 }
109 case .errorOccurred:
110 print("client stream error occurred: \(String(describing: aStream.streamError))")
111 close()
112 notifyDidClose(error: aStream.streamError)
113
114 default:
115 break
116 }
117 }
118 }
119
120 private extension SocketConnection {
121
122 func setupAddress() -> Bool {
123 var addr = sockaddr_un()
124 guard filePath.count < MemoryLayout.size(ofValue: addr.sun_path) else {
125 print("failure: fd path is too long")
126 return false
127 }
128
129 _ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in
130 filePath.withCString {
131 strncpy(ptr, $0, filePath.count)
132 }
133 }
134
135 address = addr
136 return true
137 }
138
139 func connectSocket() -> Bool {
140 guard var addr = address else {
141 return false
142 }
143
144 let status = withUnsafePointer(to: &addr) { ptr in
145 ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) {
146 Darwin.connect(socketHandle, $0, socklen_t(MemoryLayout<sockaddr_un>.size))
147 }
148 }
149
150 guard status == noErr else {
151 print("failure: \(status)")
152 return false
153 }
154
155 return true
156 }
157
158 func setupStreams() {
159 var readStream: Unmanaged<CFReadStream>?
160 var writeStream: Unmanaged<CFWriteStream>?
161
162 CFStreamCreatePairWithSocket(kCFAllocatorDefault, socketHandle, &readStream, &writeStream)
163
164 inputStream = readStream?.takeRetainedValue()
165 inputStream?.delegate = self
166 inputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
167
168 outputStream = writeStream?.takeRetainedValue()
169 outputStream?.delegate = self
170 outputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
171
172 scheduleStreams()
173 }
174
175 func scheduleStreams() {
176 shouldKeepRunning = true
177
178 networkQueue = DispatchQueue.global(qos: .userInitiated)
179 networkQueue?.async { [weak self] in
180 self?.inputStream?.schedule(in: .current, forMode: .common)
181 self?.outputStream?.schedule(in: .current, forMode: .common)
182
183 var isRunning = false
184
185 repeat {
186 isRunning = self?.shouldKeepRunning ?? false && RunLoop.current.run(mode: .default, before: .distantFuture)
187 } while (isRunning)
188 }
189 }
190
191 func unscheduleStreams() {
192 networkQueue?.sync { [weak self] in
193 self?.inputStream?.remove(from: .current, forMode: .common)
194 self?.outputStream?.remove(from: .current, forMode: .common)
195 }
196
197 shouldKeepRunning = false
198 }
199
200 func notifyDidClose(error: Error?) {
201 if didClose != nil {
202 didClose?(error)
203 }
204 }
205 }