Socket.swift 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. return try [UInt8](unsafeUninitializedCapacity: length) { buffer, bytesRead in
  133. bytesRead = try read(into: &buffer, length: length)
  134. }
  135. }
  136. static let kBufferLength = 1024
  137. /// Read up to `length` bytes from this socket into an existing buffer
  138. ///
  139. /// - Parameter into: The buffer to read into (must be at least length bytes in size)
  140. /// - Parameter length: The maximum bytes to read
  141. /// - Returns: The number of bytes read
  142. /// - Throws: SocketError.recvFailed if unable to read bytes from the socket
  143. func read(into buffer: inout UnsafeMutableBufferPointer<UInt8>, length: Int) throws -> Int {
  144. var offset = 0
  145. guard let baseAddress = buffer.baseAddress else { return 0 }
  146. while offset < length {
  147. // Compute next read length in bytes. The bytes read is never more than kBufferLength at once.
  148. let readLength = offset + Socket.kBufferLength < length ? Socket.kBufferLength : length - offset
  149. #if os(Linux)
  150. let bytesRead = Glibc.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
  151. #else
  152. let bytesRead = Darwin.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
  153. #endif
  154. guard bytesRead > 0 else {
  155. throw SocketError.recvFailed(Errno.description())
  156. }
  157. offset += bytesRead
  158. }
  159. return offset
  160. }
  161. private static let CR: UInt8 = 13
  162. private static let NL: UInt8 = 10
  163. public func readLine() throws -> String {
  164. var characters: String = ""
  165. var index: UInt8 = 0
  166. repeat {
  167. index = try self.read()
  168. if index > Socket.CR { characters.append(Character(UnicodeScalar(index))) }
  169. } while index != Socket.NL
  170. return characters
  171. }
  172. public func peername() throws -> String {
  173. var addr = sockaddr(), len: socklen_t = socklen_t(MemoryLayout<sockaddr>.size)
  174. if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
  175. throw SocketError.getPeerNameFailed(Errno.description())
  176. }
  177. var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
  178. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  179. throw SocketError.getNameInfoFailed(Errno.description())
  180. }
  181. return String(cString: hostBuffer)
  182. }
  183. public class func setNoSigPipe(_ socket: Int32) {
  184. #if os(Linux)
  185. // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
  186. // or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
  187. #else
  188. // Prevents crashes when blocking calls are pending and the app is paused ( via Home button ).
  189. var no_sig_pipe: Int32 = 1
  190. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(MemoryLayout<Int32>.size))
  191. #endif
  192. }
  193. public class func close(_ socket: Int32) {
  194. #if os(Linux)
  195. _ = Glibc.close(socket)
  196. #else
  197. _ = Darwin.close(socket)
  198. #endif
  199. }
  200. }
  201. public func == (socket1: Socket, socket2: Socket) -> Bool {
  202. return socket1.socketFileDescriptor == socket2.socketFileDescriptor
  203. }