From dedea0de3a45224b9d9e91daf79baa9b8995457a Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 30 Aug 2018 12:18:33 +0300 Subject: [PATCH 1/4] Allow creating signature from Address --- Sources/Socket/Socket.swift | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Sources/Socket/Socket.swift b/Sources/Socket/Socket.swift index a5a707d..7496807 100644 --- a/Sources/Socket/Socket.swift +++ b/Sources/Socket/Socket.swift @@ -459,6 +459,39 @@ public class Socket: SocketReader, SocketWriter { self.address = address } + + /// + /// Create a socket signature + /// + /// - Parameters: + /// - socketType: The type of socket to create. + /// - proto: The protocool to use for the socket. + /// - address: Address info for the socket. + /// + /// - Returns: New Signature instance + /// + public init?(socketType: SocketType, proto: SocketProtocol, address: Address) throws { + + // Validate the parameters... + if socketType == .stream { + guard proto == .tcp || proto == .unix else { + + throw Error(code: Socket.SOCKET_ERR_BAD_SIGNATURE_PARAMETERS, reason: "Stream socket must use either .tcp or .unix for the protocol.") + } + } + if socketType == .datagram { + guard proto == .udp || proto == .unix else { + + throw Error(code: Socket.SOCKET_ERR_BAD_SIGNATURE_PARAMETERS, reason: "Datagram socket must use .udp or .unix for the protocol.") + } + } + + self.protocolFamily = address.family + self.socketType = socketType + self.proto = proto + + self.address = address + } /// /// Create a socket signature From a4ffe7e02701374212f5707ed11a3de9b93499b2 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 30 Aug 2018 12:27:29 +0300 Subject: [PATCH 2/4] Rearrange connect(using signature: Signature) to use address if its set before hostname Also allow creating a Signature with Address and hostname In this case the hostname is only used for SSL verification as the address is already resolved --- Sources/Socket/Socket.swift | 140 ++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/Sources/Socket/Socket.swift b/Sources/Socket/Socket.swift index 7496807..d1b8a63 100644 --- a/Sources/Socket/Socket.swift +++ b/Sources/Socket/Socket.swift @@ -467,10 +467,12 @@ public class Socket: SocketReader, SocketWriter { /// - socketType: The type of socket to create. /// - proto: The protocool to use for the socket. /// - address: Address info for the socket. + /// - hostname: Hostname for this signature. + /// - port: Port for this signature. /// /// - Returns: New Signature instance /// - public init?(socketType: SocketType, proto: SocketProtocol, address: Address) throws { + public init?(socketType: SocketType, proto: SocketProtocol, address: Address, hostname: String?, port: Int32?) throws { // Validate the parameters... if socketType == .stream { @@ -491,6 +493,10 @@ public class Socket: SocketReader, SocketWriter { self.proto = proto self.address = address + self.hostname = hostname + if let port = port { + self.port = port + } } /// @@ -2011,83 +2017,77 @@ public class Socket: SocketReader, SocketWriter { try self.connect(to: path) return } - - if signature.hostname == nil || signature.port == Socket.SOCKET_INVALID_PORT { - - guard let _ = signature.address else { - - throw Error(code: Socket.SOCKET_ERR_MISSING_CONNECTION_DATA, reason: "Unable to access connection data.") + + if let address = signature.address { + // Tell the delegate to initialize as a client... + do { + + try self.delegate?.initialize(asServer: false) + + } catch let error { + + guard let sslError = error as? SSLError else { + + throw error + } + + throw Error(with: sslError) } - - } else { - - // Otherwise, make sure we've got a hostname and port... - guard let hostname = signature.hostname, - signature.port != Socket.SOCKET_INVALID_PORT else { - - throw Error(code: Socket.SOCKET_ERR_MISSING_CONNECTION_DATA, reason: "Unable to access hostname and port.") + + // Now, do the connection using the supplied address... + let rc = address.withSockAddrPointer { sockaddr, length -> Int32 in + #if os(Linux) + return Glibc.connect(self.socketfd, sockaddr, length) + #else + return Darwin.connect(self.socketfd, sockaddr, length) + #endif } + + if rc < 0 { + + throw Error(code: Socket.SOCKET_ERR_CONNECT_FAILED, reason: self.lastError()) + } + + if signature.hostname != nil, signature.port != Socket.SOCKET_INVALID_PORT { + self.signature = signature + self.isConnected = true + } else if let (hostname, port) = Socket.hostnameAndPort(from: signature.address!) { + var sig = signature + sig.hostname = hostname + sig.port = Int32(port) + self.signature = sig + self.isConnected = true + } + + // Let the delegate do post connect handling and verification... + do { + + if self.delegate != nil { + try self.delegate?.onConnect(socket: self) + self.signature?.isSecure = true + } + + } catch let error { + + guard let sslError = error as? SSLError else { + + throw error + } + + throw Error(with: sslError) + } + + return + } + + if let hostname = signature.hostname, signature.port != Socket.SOCKET_INVALID_PORT { // Connect using hostname and port.... try self.connect(to: hostname, port: signature.port) return } - - // Tell the delegate to initialize as a client... - do { - - try self.delegate?.initialize(asServer: false) - - } catch let error { - - guard let sslError = error as? SSLError else { - - throw error - } - - throw Error(with: sslError) - } - - // Now, do the connection using the supplied address... - let rc = signature.address!.withSockAddrPointer { sockaddr, length -> Int32 in - #if os(Linux) - return Glibc.connect(self.socketfd, sockaddr, length) - #else - return Darwin.connect(self.socketfd, sockaddr, length) - #endif - } - if rc < 0 { - - throw Error(code: Socket.SOCKET_ERR_CONNECT_FAILED, reason: self.lastError()) - } - - if let (hostname, port) = Socket.hostnameAndPort(from: signature.address!) { - - var sig = signature - sig.hostname = hostname - sig.port = Int32(port) - self.signature = sig - self.isConnected = true - } - - // Let the delegate do post connect handling and verification... - do { - - if self.delegate != nil { - try self.delegate?.onConnect(socket: self) - self.signature?.isSecure = true - } - - } catch let error { - - guard let sslError = error as? SSLError else { - - throw error - } - - throw Error(with: sslError) - } + throw Error(code: Socket.SOCKET_ERR_MISSING_CONNECTION_DATA, reason: "Unable to access connection data.") } // MARK: -- Listen From 114f6b98ea8adaaea52942781644bea18300ca71 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 30 Aug 2018 15:04:47 +0300 Subject: [PATCH 3/4] Set remoteConnectionClosed = true for all ECONNRESET --- Sources/Socket/Socket.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/Socket/Socket.swift b/Sources/Socket/Socket.swift index d1b8a63..e29b6d4 100644 --- a/Sources/Socket/Socket.swift +++ b/Sources/Socket/Socket.swift @@ -3008,7 +3008,7 @@ public class Socket: SocketReader, SocketWriter { // - Handle a connection reset by peer (ECONNRESET) and throw a different exception... if errno == ECONNRESET { - + self.remoteConnectionClosed = true throw Error(code: Socket.SOCKET_ERR_CONNECTION_RESET, reason: self.lastError()) } @@ -3139,7 +3139,7 @@ public class Socket: SocketReader, SocketWriter { // - Handle a connection reset by peer (ECONNRESET) and throw a different exception... if errno == ECONNRESET { - + self.remoteConnectionClosed = true throw Error(code: Socket.SOCKET_ERR_CONNECTION_RESET, reason: self.lastError()) } @@ -3566,6 +3566,7 @@ public class Socket: SocketReader, SocketWriter { case ECONNRESET: // - Handle a connection reset by peer (ECONNRESET) and throw a different exception... + self.remoteConnectionClosed = true throw Error(code: Socket.SOCKET_ERR_CONNECTION_RESET, reason: self.lastError()) default: @@ -3635,7 +3636,7 @@ public class Socket: SocketReader, SocketWriter { // - Handle a connection reset by peer (ECONNRESET) and throw a different exception... if errno == ECONNRESET { - + self.remoteConnectionClosed = true throw Error(code: Socket.SOCKET_ERR_CONNECTION_RESET, reason: self.lastError()) } From cdfa5bc882e36ad6d0d685fa42fac1737188ab25 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 30 Aug 2018 15:07:41 +0300 Subject: [PATCH 4/4] No need to use fallthrough in this switch --- Sources/Socket/Socket.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Sources/Socket/Socket.swift b/Sources/Socket/Socket.swift index e29b6d4..bbbb908 100644 --- a/Sources/Socket/Socket.swift +++ b/Sources/Socket/Socket.swift @@ -3559,9 +3559,7 @@ public class Socket: SocketReader, SocketWriter { // - Could be an error, but if errno is EAGAIN or EWOULDBLOCK (if a non-blocking socket), // it means there was NO data to read... - case EAGAIN: - fallthrough - case EWOULDBLOCK: + case EWOULDBLOCK, EAGAIN: return self.readStorage.length case ECONNRESET: