bump websocket

This commit is contained in:
Erik 2016-05-17 22:35:33 -04:00
parent 50216647ca
commit 3401414430
4 changed files with 89 additions and 76 deletions

View File

@ -385,7 +385,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe
doPoll() doPoll()
} }
client?.engineDidOpen?("Connect") client?.engineDidOpen("Connect")
} }
} catch { } catch {
didError("Error parsing open packet") didError("Error parsing open packet")

View File

@ -28,7 +28,7 @@ import Foundation
@objc public protocol SocketEngineClient { @objc public protocol SocketEngineClient {
func engineDidError(reason: String) func engineDidError(reason: String)
func engineDidClose(reason: String) func engineDidClose(reason: String)
optional func engineDidOpen(reason: String) func engineDidOpen(reason: String)
func parseEngineMessage(msg: String) func parseEngineMessage(msg: String)
func parseEngineBinaryData(data: NSData) func parseEngineBinaryData(data: NSData)
} }

View File

@ -284,6 +284,10 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
handleEvent("error", data: [reason], isInternalMessage: true) handleEvent("error", data: [reason], isInternalMessage: true)
} }
public func engineDidOpen(reason: String) {
DefaultSocketLogger.Logger.log(reason, type: "SocketEngineClient")
}
// Called when the socket gets an ack for something it sent // Called when the socket gets an ack for something it sent
func handleAck(ack: Int, data: [AnyObject]) { func handleAck(ack: Int, data: [AnyObject]) {
@ -296,9 +300,7 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
/// Causes an event to be handled. Only use if you know what you're doing. /// Causes an event to be handled. Only use if you know what you're doing.
public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) { public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) {
guard status == .Connected || isInternalMessage else { guard status == .Connected || isInternalMessage else { return }
return
}
DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "") DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
@ -333,14 +335,14 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable
public func off(event: String) { public func off(event: String) {
DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event) DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event)
handlers = handlers.filter { $0.event != event } handlers = handlers.filter({ $0.event != event })
} }
/// Removes a handler with the specified UUID gotten from an `on` or `once` /// Removes a handler with the specified UUID gotten from an `on` or `once`
public func off(id id: NSUUID) { public func off(id id: NSUUID) {
DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id) DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id)
handlers = handlers.filter { $0.id != id } handlers = handlers.filter({ $0.id != id })
} }
/// Adds a handler for an event. /// Adds a handler for an event.

View File

@ -112,6 +112,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
public var security: SSLSecurity? public var security: SSLSecurity?
public var enabledSSLCipherSuites: [SSLCipherSuite]? public var enabledSSLCipherSuites: [SSLCipherSuite]?
public var origin: String? public var origin: String?
public var timeout = 5
public var isConnected :Bool { public var isConnected :Bool {
return connected return connected
} }
@ -319,12 +320,12 @@ public class WebSocket : NSObject, NSStreamDelegate {
self.mutex.unlock() self.mutex.unlock()
let bytes = UnsafePointer<UInt8>(data.bytes) let bytes = UnsafePointer<UInt8>(data.bytes)
var timeout = 5000000 //wait 5 seconds before giving up var out = timeout * 1000000 //wait 5 seconds before giving up
writeQueue.addOperationWithBlock { [weak self] in writeQueue.addOperationWithBlock { [weak self] in
while !outStream.hasSpaceAvailable { while !outStream.hasSpaceAvailable {
usleep(100) //wait until the socket is ready usleep(100) //wait until the socket is ready
timeout -= 100 out -= 100
if timeout < 0 { if out < 0 {
self?.cleanupStream() self?.cleanupStream()
self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2)) self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2))
return return
@ -405,25 +406,24 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
///dequeue the incoming input so it is processed in order ///dequeue the incoming input so it is processed in order
private func dequeueInput() { private func dequeueInput() {
guard !inputQueue.isEmpty else { return } while !inputQueue.isEmpty {
let data = inputQueue[0]
let data = inputQueue[0] var work = data
var work = data if let fragBuffer = fragBuffer {
if let fragBuffer = fragBuffer { let combine = NSMutableData(data: fragBuffer)
let combine = NSMutableData(data: fragBuffer) combine.appendData(data)
combine.appendData(data) work = combine
work = combine self.fragBuffer = nil
self.fragBuffer = nil }
let buffer = UnsafePointer<UInt8>(work.bytes)
let length = work.length
if !connected {
processTCPHandshake(buffer, bufferLen: length)
} else {
processRawMessagesInBuffer(buffer, bufferLen: length)
}
inputQueue = inputQueue.filter{$0 != data}
} }
let buffer = UnsafePointer<UInt8>(work.bytes)
let length = work.length
if !connected {
processTCPHandshake(buffer, bufferLen: length)
} else {
processRawMessage(buffer, bufferLen: length)
}
inputQueue = inputQueue.filter{$0 != data}
dequeueInput()
} }
//handle checking the inital connection status //handle checking the inital connection status
@ -469,7 +469,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
totalSize += 1 //skip the last \n totalSize += 1 //skip the last \n
let restSize = bufferLen - totalSize let restSize = bufferLen - totalSize
if restSize > 0 { if restSize > 0 {
processRawMessage((buffer+totalSize),bufferLen: restSize) processRawMessagesInBuffer(buffer + totalSize, bufferLen: restSize)
} }
return 0 //success return 0 //success
} }
@ -522,12 +522,15 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
} }
///process the websocket data /// Process one message at the start of `buffer`. Return another buffer (sharing storage) that contains the leftover contents of `buffer` that I didn't process.
private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) { @warn_unused_result
private func processOneRawMessage(inBuffer buffer: UnsafeBufferPointer<UInt8>) -> UnsafeBufferPointer<UInt8> {
let response = readStack.last let response = readStack.last
let baseAddress = buffer.baseAddress
let bufferLen = buffer.count
if response != nil && bufferLen < 2 { if response != nil && bufferLen < 2 {
fragBuffer = NSData(bytes: buffer, length: bufferLen) fragBuffer = NSData(buffer: buffer)
return return emptyBuffer
} }
if let response = response where response.bytesLeft > 0 { if let response = response where response.bytesLeft > 0 {
var len = response.bytesLeft var len = response.bytesLeft
@ -537,24 +540,20 @@ public class WebSocket : NSObject, NSStreamDelegate {
extra = 0 extra = 0
} }
response.bytesLeft -= len response.bytesLeft -= len
response.buffer?.appendData(NSData(bytes: buffer, length: len)) response.buffer?.appendData(NSData(bytes: baseAddress, length: len))
processResponse(response) processResponse(response)
let offset = bufferLen - extra return buffer.fromOffset(bufferLen - extra)
if extra > 0 {
processExtra((buffer+offset), bufferLen: extra)
}
return
} else { } else {
let isFin = (FinMask & buffer[0]) let isFin = (FinMask & baseAddress[0])
let receivedOpcode = OpCode(rawValue: (OpCodeMask & buffer[0])) let receivedOpcode = OpCode(rawValue: (OpCodeMask & baseAddress[0]))
let isMasked = (MaskMask & buffer[1]) let isMasked = (MaskMask & baseAddress[1])
let payloadLen = (PayloadLenMask & buffer[1]) let payloadLen = (PayloadLenMask & baseAddress[1])
var offset = 2 var offset = 2
if (isMasked > 0 || (RSVMask & buffer[0]) > 0) && receivedOpcode != .Pong { if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .Pong {
let errCode = CloseCode.ProtocolError.rawValue let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode)) doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode))
writeError(errCode) writeError(errCode)
return return emptyBuffer
} }
let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping) let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping)
if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame && if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame &&
@ -562,20 +561,20 @@ public class WebSocket : NSObject, NSStreamDelegate {
let errCode = CloseCode.ProtocolError.rawValue let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode)) doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode))
writeError(errCode) writeError(errCode)
return return emptyBuffer
} }
if isControlFrame && isFin == 0 { if isControlFrame && isFin == 0 {
let errCode = CloseCode.ProtocolError.rawValue let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("control frames can't be fragmented", code: errCode)) doDisconnect(errorWithDetail("control frames can't be fragmented", code: errCode))
writeError(errCode) writeError(errCode)
return return emptyBuffer
} }
if receivedOpcode == .ConnectionClose { if receivedOpcode == .ConnectionClose {
var code = CloseCode.Normal.rawValue var code = CloseCode.Normal.rawValue
if payloadLen == 1 { if payloadLen == 1 {
code = CloseCode.ProtocolError.rawValue code = CloseCode.ProtocolError.rawValue
} else if payloadLen > 1 { } else if payloadLen > 1 {
code = WebSocket.readUint16(buffer, offset: offset) code = WebSocket.readUint16(baseAddress, offset: offset)
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) { if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
code = CloseCode.ProtocolError.rawValue code = CloseCode.ProtocolError.rawValue
} }
@ -584,7 +583,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
if payloadLen > 2 { if payloadLen > 2 {
let len = Int(payloadLen-2) let len = Int(payloadLen-2)
if len > 0 { if len > 0 {
let bytes = UnsafePointer<UInt8>((buffer+offset)) let bytes = baseAddress + offset
let str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding) let str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding)
if str == nil { if str == nil {
code = CloseCode.ProtocolError.rawValue code = CloseCode.ProtocolError.rawValue
@ -593,23 +592,23 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
doDisconnect(errorWithDetail("connection closed by server", code: code)) doDisconnect(errorWithDetail("connection closed by server", code: code))
writeError(code) writeError(code)
return return emptyBuffer
} }
if isControlFrame && payloadLen > 125 { if isControlFrame && payloadLen > 125 {
writeError(CloseCode.ProtocolError.rawValue) writeError(CloseCode.ProtocolError.rawValue)
return return emptyBuffer
} }
var dataLength = UInt64(payloadLen) var dataLength = UInt64(payloadLen)
if dataLength == 127 { if dataLength == 127 {
dataLength = WebSocket.readUint64(buffer, offset: offset) dataLength = WebSocket.readUint64(baseAddress, offset: offset)
offset += sizeof(UInt64) offset += sizeof(UInt64)
} else if dataLength == 126 { } else if dataLength == 126 {
dataLength = UInt64(WebSocket.readUint16(buffer, offset: offset)) dataLength = UInt64(WebSocket.readUint16(baseAddress, offset: offset))
offset += sizeof(UInt16) offset += sizeof(UInt16)
} }
if bufferLen < offset || UInt64(bufferLen - offset) < dataLength { if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
fragBuffer = NSData(bytes: buffer, length: bufferLen) fragBuffer = NSData(bytes: baseAddress, length: bufferLen)
return return emptyBuffer
} }
var len = dataLength var len = dataLength
if dataLength > UInt64(bufferLen) { if dataLength > UInt64(bufferLen) {
@ -620,7 +619,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
len = 0 len = 0
data = NSData() data = NSData()
} else { } else {
data = NSData(bytes: UnsafePointer<UInt8>((buffer+offset)), length: Int(len)) data = NSData(bytes: baseAddress+offset, length: Int(len))
} }
if receivedOpcode == .Pong { if receivedOpcode == .Pong {
if canDispatch { if canDispatch {
@ -630,12 +629,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
s.pongDelegate?.websocketDidReceivePong(s) s.pongDelegate?.websocketDidReceivePong(s)
} }
} }
let step = Int(offset+numericCast(len)) return buffer.fromOffset(offset + Int(len))
let extra = bufferLen-step
if extra > 0 {
processRawMessage((buffer+step), bufferLen: extra)
}
return
} }
var response = readStack.last var response = readStack.last
if isControlFrame { if isControlFrame {
@ -645,7 +639,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
let errCode = CloseCode.ProtocolError.rawValue let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("continue frame before a binary or text frame", code: errCode)) doDisconnect(errorWithDetail("continue frame before a binary or text frame", code: errCode))
writeError(errCode) writeError(errCode)
return return emptyBuffer
} }
var isNew = false var isNew = false
if response == nil { if response == nil {
@ -654,7 +648,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
doDisconnect(errorWithDetail("first frame can't be a continue frame", doDisconnect(errorWithDetail("first frame can't be a continue frame",
code: errCode)) code: errCode))
writeError(errCode) writeError(errCode)
return return emptyBuffer
} }
isNew = true isNew = true
response = WSResponse() response = WSResponse()
@ -669,7 +663,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
doDisconnect(errorWithDetail("second and beyond of fragment message must be a continue frame", doDisconnect(errorWithDetail("second and beyond of fragment message must be a continue frame",
code: errCode)) code: errCode))
writeError(errCode) writeError(errCode)
return return emptyBuffer
} }
response!.buffer!.appendData(data) response!.buffer!.appendData(data)
} }
@ -684,20 +678,18 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
let step = Int(offset+numericCast(len)) let step = Int(offset+numericCast(len))
let extra = bufferLen-step return buffer.fromOffset(step)
if extra > 0 {
processExtra((buffer+step), bufferLen: extra)
}
} }
} }
///process the extra of a buffer /// Process all messages in the buffer if possible.
private func processExtra(buffer: UnsafePointer<UInt8>, bufferLen: Int) { private func processRawMessagesInBuffer(pointer: UnsafePointer<UInt8>, bufferLen: Int) {
if bufferLen < 2 { var buffer = UnsafeBufferPointer(start: pointer, count: bufferLen)
fragBuffer = NSData(bytes: buffer, length: bufferLen) repeat {
} else { buffer = processOneRawMessage(inBuffer: buffer)
processRawMessage(buffer, bufferLen: bufferLen) } while buffer.count >= 2
if buffer.count > 0 {
fragBuffer = NSData(buffer: buffer)
} }
} }
@ -835,6 +827,25 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
private extension NSData {
convenience init(buffer: UnsafeBufferPointer<UInt8>) {
self.init(bytes: buffer.baseAddress, length: buffer.count)
}
}
private extension UnsafeBufferPointer {
func fromOffset(offset: Int) -> UnsafeBufferPointer<Element> {
return UnsafeBufferPointer<Element>(start: baseAddress.advancedBy(offset), count: count - offset)
}
}
private let emptyBuffer = UnsafeBufferPointer<UInt8>(start: nil, count: 0)
public class SSLCert { public class SSLCert {
var certData: NSData? var certData: NSData?
var key: SecKeyRef? var key: SecKeyRef?