1
0

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