From b2dd8fdc6619637fa8263bd511cdc4a327a888b8 Mon Sep 17 00:00:00 2001 From: Bill Abt Date: Mon, 5 Dec 2016 15:07:42 -0500 Subject: [PATCH] Added more UDP infrastructure. --- Sources/Socket.swift | 266 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 229 insertions(+), 37 deletions(-) diff --git a/Sources/Socket.swift b/Sources/Socket.swift index 323bc18..321704b 100644 --- a/Sources/Socket.swift +++ b/Sources/Socket.swift @@ -1808,6 +1808,8 @@ public class Socket: SocketReader, SocketWriter { // MARK: -- Listen + // MARK: --- TCP + /// /// Listen on a port, limiting the maximum number of pending connections. /// @@ -1841,19 +1843,23 @@ public class Socket: SocketReader, SocketWriter { throw Error(code: Socket.SOCKET_ERR_INTERNAL, reason: "Socket signature not found.") } - // Tell the delegate to initialize as a server... - do { + // No SSL over UDP... + if sig.socketType != .datagram && sig.proto != .udp { + + // Tell the delegate to initialize as a server... + do { - try self.delegate?.initialize(asServer: true) + try self.delegate?.initialize(asServer: true) - } catch let error { + } catch let error { - guard let sslError = error as? SSLError else { + guard let sslError = error as? SSLError else { - throw error - } + throw error + } - throw Error(with: sslError) + throw Error(with: sslError) + } } // Create the hints for our search... @@ -1993,6 +1999,14 @@ public class Socket: SocketReader, SocketWriter { self.signature?.port = Int32(port) } + self.signature?.isBound = true + self.signature?.address = address + + // We don't actually listen for connections with a UDP socket, so we skip the next steps... + if sig.socketType == .datagram && sig.proto == .udp { + return + } + // Now listen for connections... #if os(Linux) if Glibc.listen(self.socketfd, Int32(maxBacklogSize)) < 0 { @@ -2007,11 +2021,11 @@ public class Socket: SocketReader, SocketWriter { #endif self.isListening = true - self.signature?.address = address - self.signature?.isBound = true self.signature?.isSecure = self.delegate != nil ? true : false } + // MARK: --- UNIX + /// /// Listen on a path, limiting the maximum number of pending connections. /// @@ -2092,6 +2106,129 @@ public class Socket: SocketReader, SocketWriter { self.signature?.address = signature.address } + // MARK: --- UDP + + /// + /// Listen for a message on a UDP socket. + /// + /// - Parameters: + /// - buffer: The buffer to return the data in. + /// - bufSize: The size of the buffer. + /// - port: Port to listen on. + /// - maxBacklogSize: The maximum size of the queue containing pending connections. Default is *Socket.SOCKET_DEFAULT_MAX_BACKLOG*. + /// + /// - Returns: Tuple containing the number of bytes read and the `Address` of the client who sent the data. + /// + public func listen(forMessage buffer: UnsafeMutablePointer, bufSize: Int, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) throws -> (bytesRead: Int32, address: Address?) { + + // Make sure the buffer is valid... + if bufSize == 0 { + + throw Error(code: Socket.SOCKET_ERR_INVALID_BUFFER, reason: nil) + } + + // The socket must've been created... + if self.socketfd == Socket.SOCKET_INVALID_DESCRIPTOR { + + throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) + } + + // The socket must've been created for UDP... + guard let sig = self.signature, + sig.socketType == .datagram && sig.proto == .udp else { + + throw Error(code: Socket.SOCKET_ERR_WRONG_PROTOCOL, reason: "This is not a UDP socket.") + } + + // Set up the socket for listening for a message... + try self.listen(on: port, maxBacklogSize: maxBacklogSize) + + // If we're not bound, something went wrong... + guard sig.isBound == true else { + + throw Error(code: Socket.SOCKET_ERR_LISTEN_FAILED, reason: "") + } + + + return (0, nil) + } + + /// + /// Listen for a message on a UDP socket. + /// + /// - Parameters: + /// - data: Data buffer to receive the data read. + /// - port: Port to listen on. + /// - maxBacklogSize: The maximum size of the queue containing pending connections. Default is *Socket.SOCKET_DEFAULT_MAX_BACKLOG*. + /// + /// - Returns: Tuple containing the number of bytes read and the `Address` of the client who sent the data. + /// + public func listen(forMessage data: NSMutableData, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) throws -> (bytesRead: Int32, address: Address?) { + + // The socket must've been created... + if self.socketfd == Socket.SOCKET_INVALID_DESCRIPTOR { + + throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) + } + + // The socket must've been created for UDP... + guard let sig = self.signature, + sig.socketType == .datagram && sig.proto == .udp else { + + throw Error(code: Socket.SOCKET_ERR_WRONG_PROTOCOL, reason: "This is not a UDP socket.") + } + + // Set up the socket for listening for a message... + try self.listen(on: port, maxBacklogSize: maxBacklogSize) + + // If we're not bound, something went wrong... + guard sig.isBound == true else { + + throw Error(code: Socket.SOCKET_ERR_LISTEN_FAILED, reason: "") + } + + + return (0, nil) + } + + /// + /// Listen for a message on a UDP socket. + /// + /// - Parameters: + /// - data: Data buffer to receive the data read. + /// - port: Port to listen on. + /// - maxBacklogSize: The maximum size of the queue containing pending connections. Default is *Socket.SOCKET_DEFAULT_MAX_BACKLOG*. + /// + /// - Returns: Tuple containing the number of bytes read and the `Address` of the client who sent the data. + /// + public func listen(forMessage data: inout Data, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) throws -> (bytesRead: Int32, address: Address?) { + + // The socket must've been created... + if self.socketfd == Socket.SOCKET_INVALID_DESCRIPTOR { + + throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) + } + + // The socket must've been created for UDP... + guard let sig = self.signature, + sig.socketType == .datagram && sig.proto == .udp else { + + throw Error(code: Socket.SOCKET_ERR_WRONG_PROTOCOL, reason: "This is not a UDP socket.") + } + + // Set up the socket for listening for a message... + try self.listen(on: port, maxBacklogSize: maxBacklogSize) + + // If we're not bound, something went wrong... + guard sig.isBound == true else { + + throw Error(code: Socket.SOCKET_ERR_LISTEN_FAILED, reason: "") + } + + + return (0, nil) + } + // MARK: -- Read // MARK: --- TCP/UNIX @@ -2294,33 +2431,6 @@ public class Socket: SocketReader, SocketWriter { // MARK: --- UDP - /// - /// Read data from a UDP socket. - /// - /// - Parameters: - /// - data: The buffer to return the data in. - /// - address: Address to write data to. - /// - /// - Returns: The number of bytes returned in the buffer. - /// - public func read(into data: NSMutableData, from address: Address) throws -> (bytesRead: Int, address: Address?) { - - // The socket must've been created... - if self.socketfd == Socket.SOCKET_INVALID_DESCRIPTOR { - - throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) - } - - // The socket must've been created for UDP... - guard let sig = self.signature, - sig.proto == .udp else { - - throw Error(code: Socket.SOCKET_ERR_WRONG_PROTOCOL, reason: "This is not a UDP socket.") - } - - return (0, nil) - } - /// /// Read data from a UDP socket. /// @@ -2349,6 +2459,33 @@ public class Socket: SocketReader, SocketWriter { throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) } + // The socket must've been created for UDP... + guard let sig = self.signature, + sig.proto == .udp else { + + throw Error(code: Socket.SOCKET_ERR_WRONG_PROTOCOL, reason: "This is not a UDP socket.") + } + + return (0, nil) + } + + /// + /// Read data from a UDP socket. + /// + /// - Parameters: + /// - data: The buffer to return the data in. + /// - address: Address to write data to. + /// + /// - Returns: The number of bytes returned in the buffer. + /// + public func read(into data: NSMutableData, from address: Address) throws -> (bytesRead: Int, address: Address?) { + + // The socket must've been created... + if self.socketfd == Socket.SOCKET_INVALID_DESCRIPTOR { + + throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) + } + // The socket must've been created for UDP... guard let sig = self.signature, sig.proto == .udp else { @@ -2359,6 +2496,33 @@ public class Socket: SocketReader, SocketWriter { return (0, nil) } + /// + /// Read data from a UDP socket. + /// + /// - Parameters: + /// - data: The buffer to return the data in. + /// - address: Address to write data to. + /// + /// - Returns: The number of bytes returned in the buffer. + /// + public func read(into data: inout Data, from address: Address) throws -> (bytesRead: Int, address: Address?) { + + // The socket must've been created... + if self.socketfd == Socket.SOCKET_INVALID_DESCRIPTOR { + + throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) + } + + // The socket must've been created for UDP... + guard let sig = self.signature, + sig.proto == .udp else { + + throw Error(code: Socket.SOCKET_ERR_WRONG_PROTOCOL, reason: "This is not a UDP socket.") + } + + return (0, nil) + } + // MARK: -- Write // MARK: --- TCP/UNIX @@ -2585,6 +2749,34 @@ public class Socket: SocketReader, SocketWriter { } } + /// + /// Write data to a UDP socket. + /// + /// - Parameters: + /// - data: The Data object containing the data to write. + /// - address: Address to write data to. + /// + public func write(from data: Data, to addresss: Address) throws { + + // The socket must've been created... + if self.socketfd == Socket.SOCKET_INVALID_DESCRIPTOR { + + throw Error(code: Socket.SOCKET_ERR_BAD_DESCRIPTOR, reason: nil) + } + + // The socket must've been created for UDP... + guard let sig = self.signature, + sig.proto == .udp else { + + throw Error(code: Socket.SOCKET_ERR_WRONG_PROTOCOL, reason: "This is not a UDP socket.") + } + + // If there's no data in the NSData object, why bother? Fail silently... + if data.count == 0 { + return + } + } + // MARK: -- Utility ///