Socket.swift 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. //
  2. // Socket.swift
  3. // Swifter
  4. //
  5. // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. import Foundation
  8. public enum SocketError: Error {
  9. case socketCreationFailed(String)
  10. case socketSettingReUseAddrFailed(String)
  11. case bindFailed(String)
  12. case listenFailed(String)
  13. case writeFailed(String)
  14. case getPeerNameFailed(String)
  15. case convertingPeerNameFailed
  16. case getNameInfoFailed(String)
  17. case acceptFailed(String)
  18. case recvFailed(String)
  19. case getSockNameFailed(String)
  20. }
  21. // swiftlint: disable identifier_name
  22. open class Socket: Hashable, Equatable {
  23. let socketFileDescriptor: Int32
  24. private var shutdown = false
  25. public init(socketFileDescriptor: Int32) {
  26. self.socketFileDescriptor = socketFileDescriptor
  27. }
  28. deinit {
  29. close()
  30. }
  31. public func hash(into hasher: inout Hasher) {
  32. hasher.combine(self.socketFileDescriptor)
  33. }
  34. public func close() {
  35. if shutdown {
  36. return
  37. }
  38. shutdown = true
  39. Socket.close(self.socketFileDescriptor)
  40. }
  41. public func port() throws -> in_port_t {
  42. var addr = sockaddr_in()
  43. return try withUnsafePointer(to: &addr) { pointer in
  44. var len = socklen_t(MemoryLayout<sockaddr_in>.size)
  45. if getsockname(socketFileDescriptor, UnsafeMutablePointer(OpaquePointer(pointer)), &len) != 0 {
  46. throw SocketError.getSockNameFailed(Errno.description())
  47. }
  48. let sin_port = pointer.pointee.sin_port
  49. #if os(Linux)
  50. return ntohs(sin_port)
  51. #else
  52. return Int(OSHostByteOrder()) != OSLittleEndian ? sin_port.littleEndian : sin_port.bigEndian
  53. #endif
  54. }
  55. }
  56. public func isIPv4() throws -> Bool {
  57. var addr = sockaddr_in()
  58. return try withUnsafePointer(to: &addr) { pointer in
  59. var len = socklen_t(MemoryLayout<sockaddr_in>.size)
  60. if getsockname(socketFileDescriptor, UnsafeMutablePointer(OpaquePointer(pointer)), &len) != 0 {
  61. throw SocketError.getSockNameFailed(Errno.description())
  62. }
  63. return Int32(pointer.pointee.sin_family) == AF_INET
  64. }
  65. }
  66. public func writeUTF8(_ string: String) throws {
  67. try writeUInt8(ArraySlice(string.utf8))
  68. }
  69. public func writeUInt8(_ data: [UInt8]) throws {
  70. try writeUInt8(ArraySlice(data))
  71. }
  72. public func writeUInt8(_ data: ArraySlice<UInt8>) throws {
  73. try data.withUnsafeBufferPointer {
  74. try writeBuffer($0.baseAddress!, length: data.count)
  75. }
  76. }
  77. public func writeData(_ data: NSData) throws {
  78. try writeBuffer(data.bytes, length: data.length)
  79. }
  80. public func writeData(_ data: Data) throws {
  81. #if compiler(>=5.0)
  82. try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) -> Void in
  83. if let baseAddress = body.baseAddress, body.count > 0 {
  84. let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
  85. try self.writeBuffer(pointer, length: data.count)
  86. }
  87. }
  88. #else
  89. try data.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) -> Void in
  90. try self.writeBuffer(pointer, length: data.count)
  91. }
  92. #endif
  93. }
  94. private func writeBuffer(_ pointer: UnsafeRawPointer, length: Int) throws {
  95. var sent = 0
  96. while sent < length {
  97. #if os(Linux)
  98. let result = send(self.socketFileDescriptor, pointer + sent, Int(length - sent), Int32(MSG_NOSIGNAL))
  99. #else
  100. let result = write(self.socketFileDescriptor, pointer + sent, Int(length - sent))
  101. #endif
  102. if result <= 0 {
  103. throw SocketError.writeFailed(Errno.description())
  104. }
  105. sent += result
  106. }
  107. }
  108. /// Read a single byte off the socket. This method is optimized for reading
  109. /// a single byte. For reading multiple bytes, use read(length:), which will
  110. /// pre-allocate heap space and read directly into it.
  111. ///
  112. /// - Returns: A single byte
  113. /// - Throws: SocketError.recvFailed if unable to read from the socket
  114. open func read() throws -> UInt8 {
  115. var byte: UInt8 = 0
  116. #if os(Linux)
  117. let count = Glibc.read(self.socketFileDescriptor as Int32, &byte, 1)
  118. #else
  119. let count = Darwin.read(self.socketFileDescriptor as Int32, &byte, 1)
  120. #endif
  121. guard count > 0 else {
  122. throw SocketError.recvFailed(Errno.description())
  123. }
  124. return byte
  125. }
  126. /// Read up to `length` bytes from this socket
  127. ///
  128. /// - Parameter length: The maximum bytes to read
  129. /// - Returns: A buffer containing the bytes read
  130. /// - Throws: SocketError.recvFailed if unable to read bytes from the socket
  131. open func read(length: Int) throws -> [UInt8] {
  132. var buffer = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: length)
  133. let bytesRead = try read(into: &buffer, length: length)
  134. let rv = [UInt8](buffer[0..<bytesRead])
  135. buffer.deallocate()
  136. return rv
  137. }
  138. static let kBufferLength = 1024
  139. /// Read up to `length` bytes from this socket into an existing buffer
  140. ///
  141. /// - Parameter into: The buffer to read into (must be at least length bytes in size)
  142. /// - Parameter length: The maximum bytes to read
  143. /// - Returns: The number of bytes read
  144. /// - Throws: SocketError.recvFailed if unable to read bytes from the socket
  145. func read(into buffer: inout UnsafeMutableBufferPointer<UInt8>, length: Int) throws -> Int {
  146. var offset = 0
  147. guard let baseAddress = buffer.baseAddress else { return 0 }
  148. while offset < length {
  149. // Compute next read length in bytes. The bytes read is never more than kBufferLength at once.
  150. let readLength = offset + Socket.kBufferLength < length ? Socket.kBufferLength : length - offset
  151. #if os(Linux)
  152. let bytesRead = Glibc.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
  153. #else
  154. let bytesRead = Darwin.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
  155. #endif
  156. guard bytesRead > 0 else {
  157. throw SocketError.recvFailed(Errno.description())
  158. }
  159. offset += bytesRead
  160. }
  161. return offset
  162. }
  163. private static let CR: UInt8 = 13
  164. private static let NL: UInt8 = 10
  165. public func readLine() throws -> String {
  166. var characters: String = ""
  167. var index: UInt8 = 0
  168. repeat {
  169. index = try self.read()
  170. if index > Socket.CR { characters.append(Character(UnicodeScalar(index))) }
  171. } while index != Socket.NL
  172. return characters
  173. }
  174. public func peername() throws -> String {
  175. var addr = sockaddr(), len: socklen_t = socklen_t(MemoryLayout<sockaddr>.size)
  176. if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
  177. throw SocketError.getPeerNameFailed(Errno.description())
  178. }
  179. var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
  180. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  181. throw SocketError.getNameInfoFailed(Errno.description())
  182. }
  183. return String(cString: hostBuffer)
  184. }
  185. public class func setNoSigPipe(_ socket: Int32) {
  186. #if os(Linux)
  187. // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
  188. // or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
  189. #else
  190. // Prevents crashes when blocking calls are pending and the app is paused ( via Home button ).
  191. var no_sig_pipe: Int32 = 1
  192. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(MemoryLayout<Int32>.size))
  193. #endif
  194. }
  195. public class func close(_ socket: Int32) {
  196. #if os(Linux)
  197. _ = Glibc.close(socket)
  198. #else
  199. _ = Darwin.close(socket)
  200. #endif
  201. }
  202. }
  203. public func == (socket1: Socket, socket2: Socket) -> Bool {
  204. return socket1.socketFileDescriptor == socket2.socketFileDescriptor
  205. }