diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 1a4c1385..5c594349 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -385,7 +385,7 @@ public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWe doPoll() } - client?.engineDidOpen?("Connect") + client?.engineDidOpen("Connect") } } catch { didError("Error parsing open packet") diff --git a/Source/SocketEngineClient.swift b/Source/SocketEngineClient.swift index a1db7f67..e3aecc6f 100644 --- a/Source/SocketEngineClient.swift +++ b/Source/SocketEngineClient.swift @@ -28,7 +28,7 @@ import Foundation @objc public protocol SocketEngineClient { func engineDidError(reason: String) func engineDidClose(reason: String) - optional func engineDidOpen(reason: String) + func engineDidOpen(reason: String) func parseEngineMessage(msg: String) func parseEngineBinaryData(data: NSData) } diff --git a/Source/SocketIOClient.swift b/Source/SocketIOClient.swift index f0f12c06..835a7b56 100644 --- a/Source/SocketIOClient.swift +++ b/Source/SocketIOClient.swift @@ -284,6 +284,10 @@ public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable 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 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. public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) { - guard status == .Connected || isInternalMessage else { - return - } + guard status == .Connected || isInternalMessage else { return } 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) { 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` public func off(id id: NSUUID) { 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. diff --git a/Source/WebSocket.swift b/Source/WebSocket.swift index 833eece5..8db427b7 100644 --- a/Source/WebSocket.swift +++ b/Source/WebSocket.swift @@ -112,6 +112,7 @@ public class WebSocket : NSObject, NSStreamDelegate { public var security: SSLSecurity? public var enabledSSLCipherSuites: [SSLCipherSuite]? public var origin: String? + public var timeout = 5 public var isConnected :Bool { return connected } @@ -319,12 +320,12 @@ public class WebSocket : NSObject, NSStreamDelegate { self.mutex.unlock() let bytes = UnsafePointer(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 while !outStream.hasSpaceAvailable { usleep(100) //wait until the socket is ready - timeout -= 100 - if timeout < 0 { + out -= 100 + if out < 0 { self?.cleanupStream() self?.doDisconnect(self?.errorWithDetail("write wait timed out", code: 2)) return @@ -405,25 +406,24 @@ public class WebSocket : NSObject, NSStreamDelegate { } ///dequeue the incoming input so it is processed in order private func dequeueInput() { - guard !inputQueue.isEmpty else { return } - - let data = inputQueue[0] - var work = data - if let fragBuffer = fragBuffer { - let combine = NSMutableData(data: fragBuffer) - combine.appendData(data) - work = combine - self.fragBuffer = nil - } - let buffer = UnsafePointer(work.bytes) - let length = work.length - if !connected { - processTCPHandshake(buffer, bufferLen: length) - } else { - processRawMessage(buffer, bufferLen: length) + while !inputQueue.isEmpty { + let data = inputQueue[0] + var work = data + if let fragBuffer = fragBuffer { + let combine = NSMutableData(data: fragBuffer) + combine.appendData(data) + work = combine + self.fragBuffer = nil + } + let buffer = UnsafePointer(work.bytes) + let length = work.length + if !connected { + processTCPHandshake(buffer, bufferLen: length) + } else { + processRawMessagesInBuffer(buffer, bufferLen: length) + } + inputQueue = inputQueue.filter{$0 != data} } - inputQueue = inputQueue.filter{$0 != data} - dequeueInput() } //handle checking the inital connection status @@ -469,7 +469,7 @@ public class WebSocket : NSObject, NSStreamDelegate { totalSize += 1 //skip the last \n let restSize = bufferLen - totalSize if restSize > 0 { - processRawMessage((buffer+totalSize),bufferLen: restSize) + processRawMessagesInBuffer(buffer + totalSize, bufferLen: restSize) } return 0 //success } @@ -522,12 +522,15 @@ public class WebSocket : NSObject, NSStreamDelegate { } } - ///process the websocket data - private func processRawMessage(buffer: UnsafePointer, bufferLen: Int) { + /// 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. + @warn_unused_result + private func processOneRawMessage(inBuffer buffer: UnsafeBufferPointer) -> UnsafeBufferPointer { let response = readStack.last + let baseAddress = buffer.baseAddress + let bufferLen = buffer.count if response != nil && bufferLen < 2 { - fragBuffer = NSData(bytes: buffer, length: bufferLen) - return + fragBuffer = NSData(buffer: buffer) + return emptyBuffer } if let response = response where response.bytesLeft > 0 { var len = response.bytesLeft @@ -537,24 +540,20 @@ public class WebSocket : NSObject, NSStreamDelegate { extra = 0 } response.bytesLeft -= len - response.buffer?.appendData(NSData(bytes: buffer, length: len)) + response.buffer?.appendData(NSData(bytes: baseAddress, length: len)) processResponse(response) - let offset = bufferLen - extra - if extra > 0 { - processExtra((buffer+offset), bufferLen: extra) - } - return + return buffer.fromOffset(bufferLen - extra) } else { - let isFin = (FinMask & buffer[0]) - let receivedOpcode = OpCode(rawValue: (OpCodeMask & buffer[0])) - let isMasked = (MaskMask & buffer[1]) - let payloadLen = (PayloadLenMask & buffer[1]) + let isFin = (FinMask & baseAddress[0]) + let receivedOpcode = OpCode(rawValue: (OpCodeMask & baseAddress[0])) + let isMasked = (MaskMask & baseAddress[1]) + let payloadLen = (PayloadLenMask & baseAddress[1]) 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 doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode)) writeError(errCode) - return + return emptyBuffer } let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping) if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame && @@ -562,20 +561,20 @@ public class WebSocket : NSObject, NSStreamDelegate { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode)) writeError(errCode) - return + return emptyBuffer } if isControlFrame && isFin == 0 { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("control frames can't be fragmented", code: errCode)) writeError(errCode) - return + return emptyBuffer } if receivedOpcode == .ConnectionClose { var code = CloseCode.Normal.rawValue if payloadLen == 1 { code = CloseCode.ProtocolError.rawValue } 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) { code = CloseCode.ProtocolError.rawValue } @@ -584,7 +583,7 @@ public class WebSocket : NSObject, NSStreamDelegate { if payloadLen > 2 { let len = Int(payloadLen-2) if len > 0 { - let bytes = UnsafePointer((buffer+offset)) + let bytes = baseAddress + offset let str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding) if str == nil { code = CloseCode.ProtocolError.rawValue @@ -593,23 +592,23 @@ public class WebSocket : NSObject, NSStreamDelegate { } doDisconnect(errorWithDetail("connection closed by server", code: code)) writeError(code) - return + return emptyBuffer } if isControlFrame && payloadLen > 125 { writeError(CloseCode.ProtocolError.rawValue) - return + return emptyBuffer } var dataLength = UInt64(payloadLen) if dataLength == 127 { - dataLength = WebSocket.readUint64(buffer, offset: offset) + dataLength = WebSocket.readUint64(baseAddress, offset: offset) offset += sizeof(UInt64) } else if dataLength == 126 { - dataLength = UInt64(WebSocket.readUint16(buffer, offset: offset)) + dataLength = UInt64(WebSocket.readUint16(baseAddress, offset: offset)) offset += sizeof(UInt16) } if bufferLen < offset || UInt64(bufferLen - offset) < dataLength { - fragBuffer = NSData(bytes: buffer, length: bufferLen) - return + fragBuffer = NSData(bytes: baseAddress, length: bufferLen) + return emptyBuffer } var len = dataLength if dataLength > UInt64(bufferLen) { @@ -620,7 +619,7 @@ public class WebSocket : NSObject, NSStreamDelegate { len = 0 data = NSData() } else { - data = NSData(bytes: UnsafePointer((buffer+offset)), length: Int(len)) + data = NSData(bytes: baseAddress+offset, length: Int(len)) } if receivedOpcode == .Pong { if canDispatch { @@ -630,12 +629,7 @@ public class WebSocket : NSObject, NSStreamDelegate { s.pongDelegate?.websocketDidReceivePong(s) } } - let step = Int(offset+numericCast(len)) - let extra = bufferLen-step - if extra > 0 { - processRawMessage((buffer+step), bufferLen: extra) - } - return + return buffer.fromOffset(offset + Int(len)) } var response = readStack.last if isControlFrame { @@ -645,7 +639,7 @@ public class WebSocket : NSObject, NSStreamDelegate { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("continue frame before a binary or text frame", code: errCode)) writeError(errCode) - return + return emptyBuffer } var isNew = false if response == nil { @@ -654,7 +648,7 @@ public class WebSocket : NSObject, NSStreamDelegate { doDisconnect(errorWithDetail("first frame can't be a continue frame", code: errCode)) writeError(errCode) - return + return emptyBuffer } isNew = true response = WSResponse() @@ -669,7 +663,7 @@ public class WebSocket : NSObject, NSStreamDelegate { doDisconnect(errorWithDetail("second and beyond of fragment message must be a continue frame", code: errCode)) writeError(errCode) - return + return emptyBuffer } response!.buffer!.appendData(data) } @@ -684,20 +678,18 @@ public class WebSocket : NSObject, NSStreamDelegate { } let step = Int(offset+numericCast(len)) - let extra = bufferLen-step - if extra > 0 { - processExtra((buffer+step), bufferLen: extra) - } + return buffer.fromOffset(step) } - } - ///process the extra of a buffer - private func processExtra(buffer: UnsafePointer, bufferLen: Int) { - if bufferLen < 2 { - fragBuffer = NSData(bytes: buffer, length: bufferLen) - } else { - processRawMessage(buffer, bufferLen: bufferLen) + /// Process all messages in the buffer if possible. + private func processRawMessagesInBuffer(pointer: UnsafePointer, bufferLen: Int) { + var buffer = UnsafeBufferPointer(start: pointer, count: bufferLen) + repeat { + buffer = processOneRawMessage(inBuffer: buffer) + } 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) { + self.init(bytes: buffer.baseAddress, length: buffer.count) + } + +} + +private extension UnsafeBufferPointer { + + func fromOffset(offset: Int) -> UnsafeBufferPointer { + return UnsafeBufferPointer(start: baseAddress.advancedBy(offset), count: count - offset) + } + +} + +private let emptyBuffer = UnsafeBufferPointer(start: nil, count: 0) + + public class SSLCert { var certData: NSData? var key: SecKeyRef?