Skip to content

Commit 9116346

Browse files
author
David Jedeikin
authored
Merge pull request #4 from mojio/fix/andrii_m/mutex_warnings
Fix non-thread-safe mutex access
2 parents cf7aeb1 + 2a7320d commit 9116346

File tree

1 file changed

+39
-25
lines changed

1 file changed

+39
-25
lines changed

Source/WebSocket.swift

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ private class Deflater {
512512
/// WebSocket objects are bidirectional network streams that communicate over HTTP. RFC 6455.
513513
private class InnerWebSocket: Hashable {
514514
var id : Int
515-
var mutex = pthread_mutex_t()
515+
var mutex = UnsafeMutablePointer<pthread_mutex_t>.allocate(capacity: 1)
516516
let request : URLRequest!
517517
let subProtocols : [String]!
518518
var frames : [Frame] = []
@@ -611,9 +611,10 @@ private class InnerWebSocket: Hashable {
611611
func hash(into hasher: inout Hasher) {
612612
hasher.combine(id)
613613
}
614-
614+
615615
init(request: URLRequest, subProtocols : [String] = [], stub : Bool = false){
616-
pthread_mutex_init(&mutex, nil)
616+
mutex.initialize(to: pthread_mutex_t())
617+
pthread_mutex_init(mutex, nil)
617618
self.id = manager.nextId()
618619
self.request = request
619620
self.subProtocols = subProtocols
@@ -639,13 +640,14 @@ private class InnerWebSocket: Hashable {
639640
if inputBytes != nil {
640641
free(inputBytes)
641642
}
642-
pthread_mutex_init(&mutex, nil)
643+
pthread_mutex_init(mutex, nil)
644+
mutex.deallocate()
643645
}
644646
@inline(__always) fileprivate func lock(){
645-
pthread_mutex_lock(&mutex)
647+
pthread_mutex_lock(mutex)
646648
}
647649
@inline(__always) fileprivate func unlock(){
648-
pthread_mutex_unlock(&mutex)
650+
pthread_mutex_unlock(mutex)
649651
}
650652

651653
fileprivate var dirty : Bool {
@@ -1035,7 +1037,7 @@ private class InnerWebSocket: Hashable {
10351037
security = .none
10361038
}
10371039

1038-
var path = CFURLCopyPath(req.url! as CFURL?) as String
1040+
var path = CFURLCopyPath(req.url! as CFURL) as String
10391041
if path == "" {
10401042
path = "/"
10411043
}
@@ -1069,7 +1071,7 @@ private class InnerWebSocket: Hashable {
10691071
var (rdo, wro) : (InputStream?, OutputStream?)
10701072
var readStream: Unmanaged<CFReadStream>?
10711073
var writeStream: Unmanaged<CFWriteStream>?
1072-
CFStreamCreatePairWithSocketToHost(nil, addr[0] as CFString?, UInt32(Int(addr[1])!), &readStream, &writeStream);
1074+
CFStreamCreatePairWithSocketToHost(nil, addr[0] as CFString, UInt32(Int(addr[1])!), &readStream, &writeStream);
10731075
rdo = readStream!.takeRetainedValue()
10741076
wro = writeStream!.takeRetainedValue()
10751077
(rd, wr) = (rdo!, wro!)
@@ -1155,8 +1157,8 @@ private class InnerWebSocket: Hashable {
11551157
} else {
11561158
key = ""
11571159
if let r = line.range(of: ":") {
1158-
key = trim(String(line.prefix(upTo: r.lowerBound)))
1159-
value = trim(String(line.suffix(from: r.upperBound)))
1160+
key = trim(String(line[..<r.lowerBound]))
1161+
value = trim(String(line[r.upperBound...]))
11601162
}
11611163
}
11621164

@@ -1613,38 +1615,43 @@ private enum TCPConnSecurity {
16131615
private class Manager {
16141616
var queue = DispatchQueue(label: "SwiftWebSocketInstance", attributes: [])
16151617
var once = Int()
1616-
var mutex = pthread_mutex_t()
1618+
var mutex = UnsafeMutablePointer<pthread_mutex_t>.allocate(capacity: 1)
16171619
var cond = pthread_cond_t()
16181620
var websockets = Set<InnerWebSocket>()
16191621
var _nextId = 0
16201622
init(){
1621-
pthread_mutex_init(&mutex, nil)
1623+
mutex.initialize(to: pthread_mutex_t())
1624+
pthread_mutex_init(mutex, nil)
16221625
pthread_cond_init(&cond, nil)
16231626
DispatchQueue(label: "SwiftWebSocket", attributes: []).async {
16241627
var wss : [InnerWebSocket] = []
16251628
while true {
16261629
var wait = true
16271630
wss.removeAll()
1628-
pthread_mutex_lock(&self.mutex)
1631+
pthread_mutex_lock(self.mutex)
16291632
for ws in self.websockets {
16301633
wss.append(ws)
16311634
}
16321635
for ws in wss {
16331636
self.checkForConnectionTimeout(ws)
16341637
if ws.dirty {
1635-
pthread_mutex_unlock(&self.mutex)
1638+
pthread_mutex_unlock(self.mutex)
16361639
ws.step()
1637-
pthread_mutex_lock(&self.mutex)
1640+
pthread_mutex_lock(self.mutex)
16381641
wait = false
16391642
}
16401643
}
16411644
if wait {
16421645
_ = self.wait(250)
16431646
}
1644-
pthread_mutex_unlock(&self.mutex)
1647+
pthread_mutex_unlock(self.mutex)
16451648
}
16461649
}
16471650
}
1651+
deinit{
1652+
pthread_mutex_init(mutex, nil)
1653+
mutex.deallocate()
1654+
}
16481655
func checkForConnectionTimeout(_ ws : InnerWebSocket) {
16491656
if ws.rd != nil && ws.wr != nil && (ws.rd.streamStatus == .opening || ws.wr.streamStatus == .opening) {
16501657
let age = CFAbsoluteTimeGetCurrent() - ws.createdAt
@@ -1663,28 +1670,28 @@ private class Manager {
16631670
ts.tv_nsec = v1 + v2;
16641671
ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
16651672
ts.tv_nsec %= (1000 * 1000 * 1000);
1666-
return pthread_cond_timedwait(&self.cond, &self.mutex, &ts)
1673+
return pthread_cond_timedwait(&self.cond, self.mutex, &ts)
16671674
}
16681675
func signal(){
1669-
pthread_mutex_lock(&mutex)
1676+
pthread_mutex_lock(mutex)
16701677
pthread_cond_signal(&cond)
1671-
pthread_mutex_unlock(&mutex)
1678+
pthread_mutex_unlock(mutex)
16721679
}
16731680
func add(_ websocket: InnerWebSocket) {
1674-
pthread_mutex_lock(&mutex)
1681+
pthread_mutex_lock(mutex)
16751682
websockets.insert(websocket)
16761683
pthread_cond_signal(&cond)
1677-
pthread_mutex_unlock(&mutex)
1684+
pthread_mutex_unlock(mutex)
16781685
}
16791686
func remove(_ websocket: InnerWebSocket) {
1680-
pthread_mutex_lock(&mutex)
1687+
pthread_mutex_lock(mutex)
16811688
websockets.remove(websocket)
16821689
pthread_cond_signal(&cond)
1683-
pthread_mutex_unlock(&mutex)
1690+
pthread_mutex_unlock(mutex)
16841691
}
16851692
func nextId() -> Int {
1686-
pthread_mutex_lock(&mutex)
1687-
defer { pthread_mutex_unlock(&mutex) }
1693+
pthread_mutex_lock(mutex)
1694+
defer { pthread_mutex_unlock(mutex) }
16881695
_nextId += 1
16891696
return _nextId
16901697
}
@@ -1693,11 +1700,17 @@ private class Manager {
16931700
private let manager = Manager()
16941701

16951702
/// WebSocket objects are bidirectional network streams that communicate over HTTP. RFC 6455.
1703+
@objcMembers
16961704
open class WebSocket: NSObject {
16971705
fileprivate var ws: InnerWebSocket
16981706
fileprivate var id = manager.nextId()
16991707
fileprivate var opened: Bool
1708+
17001709
open override var hash: Int { return id }
1710+
open override func isEqual(_ other: Any?) -> Bool {
1711+
guard let other = other as? WebSocket else { return false }
1712+
return self.id == other.id
1713+
}
17011714

17021715
/// Create a WebSocket connection to a URL; this should be the URL to which the WebSocket server will respond.
17031716
public convenience init(_ url: String){
@@ -1861,6 +1874,7 @@ public func ==(lhs: WebSocket, rhs: WebSocket) -> Bool {
18611874

18621875
extension WebSocket {
18631876
/// The events of the WebSocket using a delegate.
1877+
@objc
18641878
public var delegate : WebSocketDelegate? {
18651879
get { return ws.eventDelegate }
18661880
set { ws.eventDelegate = newValue }

0 commit comments

Comments
 (0)