From 3376d17e41d2872f03ea7d7a79445f2a129ce02e Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 11 Sep 2018 18:23:38 -0500 Subject: [PATCH 1/2] Working on non-blocking reading --- Sources/BluetoothLinux/L2CAP.swift | 36 ++++++++++--- .../CSwiftBluetoothLinux/include/bluetooth.h | 51 +++++++++++++++++++ 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/Sources/BluetoothLinux/L2CAP.swift b/Sources/BluetoothLinux/L2CAP.swift index d774f36..b225a13 100644 --- a/Sources/BluetoothLinux/L2CAP.swift +++ b/Sources/BluetoothLinux/L2CAP.swift @@ -14,6 +14,7 @@ import Foundation import Bluetooth +import CSwiftBluetoothLinux /// L2CAP Bluetooth socket public final class L2CAPSocket: L2CAPSocketProtocol { @@ -133,7 +134,9 @@ public final class L2CAPSocket: L2CAPSocketProtocol { addressType: AddressType?) throws -> (CInt, sockaddr_l2) { // open socket - let internalSocket = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BluetoothProtocol.l2cap.rawValue) + let internalSocket = socket(AF_BLUETOOTH, + SOCK_SEQPACKET, + BluetoothProtocol.l2cap.rawValue) // error creating socket guard internalSocket >= 0 @@ -252,8 +255,13 @@ public final class L2CAPSocket: L2CAPSocketProtocol { } /// Reads from the socket. - public func recieve(_ bufferSize: Int = 1024) throws -> Data { - + public func recieve(_ bufferSize: Int = 1024) throws -> Data? { + + // check if reading buffer has data. + guard try canRead() + else { return nil } + + // read socket var buffer = [UInt8](repeating: 0, count: bufferSize) let actualByteCount = read(internalSocket, &buffer, bufferSize) @@ -264,6 +272,22 @@ public final class L2CAPSocket: L2CAPSocketProtocol { return Data(bytes: actualBytes) } + + private func canRead() throws -> Bool { + + var readSockets = FileDescriptorSet() + readSockets.zero() + readSockets.add(internalSocket) + + var time = timeval() + + let fdCount = select(internalSocket + 1, &readSockets, nil, nil, &time) + + guard fdCount != -1 + else { throw POSIXError.fromErrno! } + + return readSockets.contains(internalSocket) + } /// Write to the socket. public func send(_ data: Data) throws { @@ -389,8 +413,8 @@ struct bt_security { #if os(Linux) - public let SOCK_SEQPACKET: CInt = 5 - +let SOCK_SEQPACKET: CInt = CInt(Glibc.SOCK_SEQPACKET.rawValue) + #endif // MARK: - OS X support @@ -400,5 +424,5 @@ struct bt_security { let SO_PROTOCOL: CInt = 38 let SO_DOMAIN: CInt = 39 - + #endif diff --git a/Sources/CSwiftBluetoothLinux/include/bluetooth.h b/Sources/CSwiftBluetoothLinux/include/bluetooth.h index 12674a6..f946e68 100644 --- a/Sources/CSwiftBluetoothLinux/include/bluetooth.h +++ b/Sources/CSwiftBluetoothLinux/include/bluetooth.h @@ -7,7 +7,10 @@ */ #include +#include #include +#include +#include /** @brief Manipulates the underlying device parameters of special files. @@ -32,3 +35,51 @@ __attribute__((swift_name("HCISetBit(_:_:)"))) { *((uint32_t *) destination + (bit >> 5)) |= (1 << (bit & 31)); } + +/** + A set of file descriptors. + */ +typedef fd_set FileDescriptorSet __attribute__((swift_name("FileDescriptorSet"))); + +/** + Initializes a file descriptor set on the stack. + */ +static inline FileDescriptorSet* swift_bluetooth_fd_set_zero(FileDescriptorSet* set) +__attribute__((swift_name("FileDescriptorSet.zero(self:)"))) +{ + FD_ZERO(set); + return set; +} + +/** + Add a given file descriptor to a set. + @param fd The file descriptor to add to the set. + @param set The file descriptor set. + */ +static inline void swift_bluetooth_fd_set_add(FileDescriptorSet* set, int fileDescriptor) +__attribute__((swift_name("FileDescriptorSet.add(self:_:)"))) +{ + FD_SET(fileDescriptor, set); +} + +/** + Removed a given file descriptor from a set. + @param fd The file descriptor to add to the set. + @param set The file descriptor set. + */ +static inline void swift_bluetooth_fd_set_remove(FileDescriptorSet* set, int fileDescriptor) +__attribute__((swift_name("FileDescriptorSet.remove(self:_:)"))) +{ + FD_CLR(fileDescriptor, set); +} + +/** + Checks if a file descriptor is part of the set. + @param fd The file descriptor to to check for membership. + @param set The targeted value. + */ +static inline bool swift_bluetooth_fd_set_contains(FileDescriptorSet* set, int fileDescriptor) +__attribute__((swift_name("FileDescriptorSet.contains(self:_:)"))) +{ + return FD_ISSET(fileDescriptor, set); +} From 981076d393f462e1b72ed75b1d67505c254edcc9 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Tue, 11 Sep 2018 22:04:52 -0500 Subject: [PATCH 2/2] Working on non-blocking reading --- Sources/BluetoothLinux/L2CAP.swift | 31 ++++++++++++++++--- .../CSwiftBluetoothLinux/include/bluetooth.h | 1 + 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Sources/BluetoothLinux/L2CAP.swift b/Sources/BluetoothLinux/L2CAP.swift index b225a13..15dbde5 100644 --- a/Sources/BluetoothLinux/L2CAP.swift +++ b/Sources/BluetoothLinux/L2CAP.swift @@ -229,9 +229,14 @@ public final class L2CAPSocket: L2CAPSocketProtocol { // error accepting new connection guard client >= 0 else { throw POSIXError.fromErrno! } - return L2CAPSocket(clientSocket: client, - remoteAddress: remoteAddress, - securityLevel: securityLevel) + let newSocket = L2CAPSocket(clientSocket: client, + remoteAddress: remoteAddress, + securityLevel: securityLevel) + + // make socket non-blocking + try newSocket.setNonblocking() + + return newSocket } /// Connect to another L2CAP server. @@ -252,6 +257,9 @@ public final class L2CAPSocket: L2CAPSocketProtocol { connect(internalSocket, $0, socklen_t(MemoryLayout.size)) == 0 }) }) else { throw POSIXError.fromErrno! } + + // make socket non-blocking + try setNonblocking() } /// Reads from the socket. @@ -286,9 +294,22 @@ public final class L2CAPSocket: L2CAPSocketProtocol { guard fdCount != -1 else { throw POSIXError.fromErrno! } - return readSockets.contains(internalSocket) + return fdCount > 0 } - + + private func setNonblocking() throws { + + var flags = fcntl(internalSocket, F_GETFL, 0) + + guard flags != -1 + else { throw POSIXError.fromErrno! } + + flags = fcntl(internalSocket, F_SETFL, flags | O_NONBLOCK); + + guard flags != -1 + else { throw POSIXError.fromErrno! } + } + /// Write to the socket. public func send(_ data: Data) throws { diff --git a/Sources/CSwiftBluetoothLinux/include/bluetooth.h b/Sources/CSwiftBluetoothLinux/include/bluetooth.h index f946e68..5c4b9f7 100644 --- a/Sources/CSwiftBluetoothLinux/include/bluetooth.h +++ b/Sources/CSwiftBluetoothLinux/include/bluetooth.h @@ -83,3 +83,4 @@ __attribute__((swift_name("FileDescriptorSet.contains(self:_:)"))) { return FD_ISSET(fileDescriptor, set); } +