Skip to content

Commit 5627879

Browse files
committed
Merge branch 'development' of https://github.com/socketio/socket.io-client-swift into development
* 'development' of https://github.com/socketio/socket.io-client-swift: SocketAckEmitter.isExpected => .expected change isRequired() to isExpected() remove semicolon Update README.md add SocketAckEmitter.isRequired() Update README.md bump version bump websocket version fix Use Legacy Swift issue bump websocket version Update README.md
2 parents a82f27a + b6aaa42 commit 5627879

File tree

5 files changed

+77
-73
lines changed

5 files changed

+77
-73
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url config:@{
3939
[socket on:@"currentAmount" callback:^(NSArray* data, SocketAckEmitter* ack) {
4040
double cur = [[data objectAtIndex:0] floatValue];
4141

42-
[[socket emitWithAck:@"canUpdate" withItems:@[@(cur)]] timingOutAfter:0 callback:^(NSArray* data) {
42+
[[socket emitWithAck:@"canUpdate" with:@[@(cur)]] timingOutAfter:0 callback:^(NSArray* data) {
4343
[socket emit:@"update" withItems:@[@{@"amount": @(cur + 2.50)}]];
4444
}];
4545

@@ -95,7 +95,7 @@ Carthage
9595
-----------------
9696
Add this line to your `Cartfile`:
9797
```
98-
github "socketio/socket.io-client-swift" ~> 8.0.2 # Or latest version
98+
github "socketio/socket.io-client-swift" ~> 8.1.0 # Or latest version
9999
```
100100

101101
Run `carthage update --platform ios,macosx`.
@@ -108,7 +108,7 @@ Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`:
108108
use_frameworks!
109109

110110
target 'YourApp' do
111-
pod 'Socket.IO-Client-Swift', '~> 8.0.2' # Or latest version
111+
pod 'Socket.IO-Client-Swift', '~> 8.1.0' # Or latest version
112112
end
113113
```
114114

@@ -137,7 +137,7 @@ CocoaSeeds
137137
Add this line to your `Seedfile`:
138138

139139
```
140-
github "socketio/socket.io-client-swift", "v8.0.2", :files => "Source/*.swift" # Or latest version
140+
github "socketio/socket.io-client-swift", "v8.1.0", :files => "Source/*.swift" # Or latest version
141141
```
142142

143143
Run `seed install`.

Socket.IO-Client-Swift.podspec

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22
s.name = "Socket.IO-Client-Swift"
33
s.module_name = "SocketIO"
4-
s.version = "8.0.2"
4+
s.version = "8.1.0"
55
s.summary = "Socket.IO-client for iOS and OS X"
66
s.description = <<-DESC
77
Socket.IO-client for iOS and OS X.
@@ -14,8 +14,9 @@ Pod::Spec.new do |s|
1414
s.ios.deployment_target = '8.0'
1515
s.osx.deployment_target = '10.10'
1616
s.tvos.deployment_target = '9.0'
17-
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v8.0.2' }
17+
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v8.1.0' }
1818
s.source_files = "Source/**/*.swift"
1919
s.requires_arc = true
20+
s.pod_target_xcconfig = {'SWIFT_VERSION' => '3.0'}
2021
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
2122
end

Source/SSLSecurity.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Starscream
55
//
66
// Created by Dalton Cherry on 5/16/15.
7-
// Copyright (c) 2014-2015 Dalton Cherry.
7+
// Copyright (c) 2014-2016 Dalton Cherry.
88
//
99
// Licensed under the Apache License, Version 2.0 (the "License");
1010
// you may not use this file except in compliance with the License.
@@ -19,11 +19,14 @@
1919
// limitations under the License.
2020
//
2121
//////////////////////////////////////////////////////////////////////////////////////////////////
22-
2322
import Foundation
2423
import Security
2524

26-
public class SSLCert : NSObject {
25+
public protocol SSLTrustValidator {
26+
func isValid(_ trust: SecTrust, domain: String?) -> Bool
27+
}
28+
29+
open class SSLCert {
2730
var certData: Data?
2831
var key: SecKey?
2932

@@ -50,7 +53,7 @@ public class SSLCert : NSObject {
5053
}
5154
}
5255

53-
public class SSLSecurity : NSObject {
56+
open class SSLSecurity : SSLTrustValidator {
5457
public var validatedDN = true //should the domain name be validated?
5558

5659
var isReady = false //is the key processing done?
@@ -82,16 +85,14 @@ public class SSLSecurity : NSObject {
8285
/**
8386
Designated init
8487

85-
- parameter keys: is the certificates or public keys to use
88+
- parameter certs: is the certificates or public keys to use
8689
- parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation
8790

8891
- returns: a representation security object to be used with
8992
*/
9093
public init(certs: [SSLCert], usePublicKeys: Bool) {
9194
self.usePublicKeys = usePublicKeys
9295

93-
super.init()
94-
9596
if self.usePublicKeys {
9697
DispatchQueue.global(qos: .default).async {
9798
let pubKeys = certs.reduce([SecKey]()) { (pubKeys: [SecKey], cert: SSLCert) -> [SecKey] in

Source/SocketAckEmitter.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ import Foundation
2727
public final class SocketAckEmitter : NSObject {
2828
let socket: SocketIOClient
2929
let ackNum: Int
30+
31+
public var expected: Bool {
32+
return ackNum != -1
33+
}
3034

3135
init(socket: SocketIOClient, ackNum: Int) {
3236
self.socket = socket
@@ -44,6 +48,7 @@ public final class SocketAckEmitter : NSObject {
4448

4549
socket.emitAck(ackNum, with: items)
4650
}
51+
4752
}
4853

4954
public final class OnAckCallback : NSObject {

Source/WebSocket.swift

Lines changed: 57 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Websocket.swift
44
//
55
// Created by Dalton Cherry on 7/16/14.
6-
// Copyright (c) 2014-2015 Dalton Cherry.
6+
// Copyright (c) 2014-2016 Dalton Cherry.
77
//
88
// Licensed under the Apache License, Version 2.0 (the "License");
99
// you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
1818
// limitations under the License.
1919
//
2020
//////////////////////////////////////////////////////////////////////////////////////////////////
21-
2221
import Foundation
2322
import CoreFoundation
2423
import Security
@@ -38,7 +37,7 @@ public protocol WebSocketPongDelegate: class {
3837
func websocketDidReceivePong(socket: WebSocket, data: Data?)
3938
}
4039

41-
public class WebSocket : NSObject, StreamDelegate {
40+
open class WebSocket : NSObject, StreamDelegate {
4241

4342
enum OpCode : UInt8 {
4443
case continueFrame = 0x0
@@ -77,7 +76,6 @@ public class WebSocket : NSObject, StreamDelegate {
7776
var optionalProtocols: [String]?
7877

7978
// MARK: - Constants
80-
8179
let headerWSUpgradeName = "Upgrade"
8280
let headerWSUpgradeValue = "websocket"
8381
let headerWSHostName = "Host"
@@ -108,7 +106,6 @@ public class WebSocket : NSObject, StreamDelegate {
108106
}
109107

110108
// MARK: - Delegates
111-
112109
/// Responds to callback about new messages coming in over the WebSocket
113110
/// and also connection/disconnect messages.
114111
public weak var delegate: WebSocketDelegate?
@@ -118,7 +115,6 @@ public class WebSocket : NSObject, StreamDelegate {
118115

119116

120117
// MARK: - Block based API.
121-
122118
public var onConnect: ((Void) -> Void)?
123119
public var onDisconnect: ((NSError?) -> Void)?
124120
public var onText: ((String) -> Void)?
@@ -128,7 +124,7 @@ public class WebSocket : NSObject, StreamDelegate {
128124
public var headers = [String: String]()
129125
public var voipEnabled = false
130126
public var disableSSLCertValidation = false
131-
public var security: SSLSecurity?
127+
public var security: SSLTrustValidator?
132128
public var enabledSSLCipherSuites: [SSLCipherSuite]?
133129
public var origin: String?
134130
public var timeout = 5
@@ -139,7 +135,6 @@ public class WebSocket : NSObject, StreamDelegate {
139135
public var currentURL: URL { return url }
140136

141137
// MARK: - Private
142-
143138
private var url: URL
144139
private var inputStream: InputStream?
145140
private var outputStream: OutputStream?
@@ -198,7 +193,8 @@ public class WebSocket : NSObject, StreamDelegate {
198193
public func disconnect(forceTimeout: TimeInterval? = nil, closeCode: UInt16 = CloseCode.normal.rawValue) {
199194
switch forceTimeout {
200195
case .some(let seconds) where seconds > 0:
201-
callbackQueue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(seconds * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { [weak self] in
196+
let milliseconds = Int(seconds * 1_000)
197+
callbackQueue.asyncAfter(deadline: .now() + .milliseconds(milliseconds)) { [weak self] in
202198
self?.disconnectStream(nil)
203199
}
204200
fallthrough
@@ -213,7 +209,7 @@ public class WebSocket : NSObject, StreamDelegate {
213209
/**
214210
Write a string to the websocket. This sends it as a text frame.
215211
If you supply a non-nil completion block, I will perform it when the write completes.
216-
- parameter str: The string to write.
212+
- parameter string: The string to write.
217213
- parameter completion: The (optional) completion handler.
218214
*/
219215
public func write(string: String, completion: (() -> ())? = nil) {
@@ -305,7 +301,6 @@ public class WebSocket : NSObject, StreamDelegate {
305301
private func initStreamsWithData(_ data: Data, _ port: Int) {
306302
//higher level API we will cut over to at some point
307303
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
308-
309304
var readStream: Unmanaged<CFReadStream>?
310305
var writeStream: Unmanaged<CFWriteStream>?
311306
let h = url.host! as NSString
@@ -318,35 +313,35 @@ public class WebSocket : NSObject, StreamDelegate {
318313
if supportedSSLSchemes.contains(url.scheme!) {
319314
inStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
320315
outStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
316+
if disableSSLCertValidation {
317+
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(value: false), kCFStreamSSLPeerName: kCFNull]
318+
inStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
319+
outStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
320+
}
321+
if let cipherSuites = self.enabledSSLCipherSuites {
322+
if let sslContextIn = CFReadStreamCopyProperty(inputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext?,
323+
let sslContextOut = CFWriteStreamCopyProperty(outputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext? {
324+
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
325+
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
326+
if resIn != errSecSuccess {
327+
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
328+
disconnectStream(error)
329+
return
330+
}
331+
if resOut != errSecSuccess {
332+
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
333+
disconnectStream(error)
334+
return
335+
}
336+
}
337+
}
321338
} else {
322339
certValidated = true //not a https session, so no need to check SSL pinning
323340
}
324341
if voipEnabled {
325342
inStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
326343
outStream.setProperty(StreamNetworkServiceTypeValue.voIP as AnyObject, forKey: Stream.PropertyKey.networkServiceType)
327344
}
328-
if disableSSLCertValidation {
329-
let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(value: false), kCFStreamSSLPeerName: kCFNull]
330-
inStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
331-
outStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
332-
}
333-
if let cipherSuites = self.enabledSSLCipherSuites {
334-
if let sslContextIn = CFReadStreamCopyProperty(inputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext?,
335-
let sslContextOut = CFWriteStreamCopyProperty(outputStream, CFStreamPropertyKey(rawValue: kCFStreamPropertySSLContext)) as! SSLContext? {
336-
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
337-
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
338-
if resIn != errSecSuccess {
339-
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
340-
disconnectStream(error)
341-
return
342-
}
343-
if resOut != errSecSuccess {
344-
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
345-
disconnectStream(error)
346-
return
347-
}
348-
}
349-
}
350345

351346
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
352347
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
@@ -358,7 +353,7 @@ public class WebSocket : NSObject, StreamDelegate {
358353
self.mutex.unlock()
359354

360355
let bytes = UnsafeRawPointer((data as NSData).bytes).assumingMemoryBound(to: UInt8.self)
361-
var out = timeout * 1000000 // wait 5 seconds before giving up
356+
var out = timeout * 1_000_000 // wait 5 seconds before giving up
362357
writeQueue.addOperation { [weak self] in
363358
while !outStream.hasSpaceAvailable {
364359
usleep(100) // wait until the socket is ready
@@ -380,9 +375,9 @@ public class WebSocket : NSObject, StreamDelegate {
380375
*/
381376
public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
382377
if let sec = security, !certValidated && [.hasBytesAvailable, .hasSpaceAvailable].contains(eventCode) {
383-
let trust = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as AnyObject
378+
let trust = aStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust
384379
let domain = aStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String
385-
if sec.isValid(trust as! SecTrust, domain: domain) {
380+
if sec.isValid(trust, domain: domain) {
386381
certValidated = true
387382
} else {
388383
let error = errorWithDetail("Invalid SSL certificate", code: 1)
@@ -439,7 +434,6 @@ public class WebSocket : NSObject, StreamDelegate {
439434
let buf = NSMutableData(capacity: BUFFER_MAX)
440435
let buffer = UnsafeMutableRawPointer(mutating: buf!.bytes).assumingMemoryBound(to: UInt8.self)
441436
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
442-
443437
guard length > 0 else { return }
444438
var process = false
445439
if inputQueue.count == 0 {
@@ -635,34 +629,22 @@ public class WebSocket : NSObject, StreamDelegate {
635629
writeError(errCode)
636630
return emptyBuffer
637631
}
632+
var closeCode = CloseCode.normal.rawValue
638633
if receivedOpcode == .connectionClose {
639-
var code = CloseCode.normal.rawValue
640634
if payloadLen == 1 {
641-
code = CloseCode.protocolError.rawValue
635+
closeCode = CloseCode.protocolError.rawValue
642636
} else if payloadLen > 1 {
643-
code = WebSocket.readUint16(baseAddress, offset: offset)
644-
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
645-
code = CloseCode.protocolError.rawValue
637+
closeCode = WebSocket.readUint16(baseAddress, offset: offset)
638+
if closeCode < 1000 || (closeCode > 1003 && closeCode < 1007) || (closeCode > 1011 && closeCode < 3000) {
639+
closeCode = CloseCode.protocolError.rawValue
646640
}
647-
offset += 2
648641
}
649-
var closeReason = "connection closed by server"
650-
if payloadLen > 2 {
651-
let len = Int(payloadLen - 2)
652-
if len > 0 {
653-
let bytes = baseAddress + offset
654-
if let customCloseReason = String(data: Data(bytes: bytes, count: len), encoding: .utf8) {
655-
closeReason = customCloseReason
656-
} else {
657-
code = CloseCode.protocolError.rawValue
658-
}
659-
}
642+
if payloadLen < 2 {
643+
doDisconnect(errorWithDetail("connection closed by server", code: closeCode))
644+
writeError(closeCode)
645+
return emptyBuffer
660646
}
661-
doDisconnect(errorWithDetail(closeReason, code: code))
662-
writeError(code)
663-
return emptyBuffer
664-
}
665-
if isControlFrame && payloadLen > 125 {
647+
} else if isControlFrame && payloadLen > 125 {
666648
writeError(CloseCode.protocolError.rawValue)
667649
return emptyBuffer
668650
}
@@ -687,8 +669,24 @@ public class WebSocket : NSObject, StreamDelegate {
687669
len = 0
688670
data = Data()
689671
} else {
672+
if receivedOpcode == .connectionClose && len > 0 {
673+
let size = MemoryLayout<UInt16>.size
674+
offset += size
675+
len -= UInt64(size)
676+
}
690677
data = Data(bytes: baseAddress+offset, count: Int(len))
691678
}
679+
if receivedOpcode == .connectionClose {
680+
var closeReason = "connection closed by server"
681+
if let customCloseReason = String(data: data, encoding: .utf8) {
682+
closeReason = customCloseReason
683+
} else {
684+
closeCode = CloseCode.protocolError.rawValue
685+
}
686+
doDisconnect(errorWithDetail(closeReason, code: closeCode))
687+
writeError(closeCode)
688+
return emptyBuffer
689+
}
692690
if receivedOpcode == .pong {
693691
if canDispatch {
694692
callbackQueue.async { [weak self] in
@@ -902,7 +900,6 @@ public class WebSocket : NSObject, StreamDelegate {
902900
}
903901

904902
// MARK: - Deinit
905-
906903
deinit {
907904
mutex.lock()
908905
readyToWrite = false

0 commit comments

Comments
 (0)