Socket.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 var hashValue: Int { return Int(self.socketFileDescriptor) }
  31. public func close() {
  32. if shutdown {
  33. return
  34. }
  35. shutdown = true
  36. Socket.close(self.socketFileDescriptor)
  37. }
  38. public func port() throws -> in_port_t {
  39. var addr = sockaddr_in()
  40. return try withUnsafePointer(to: &addr) { pointer in
  41. var len = socklen_t(MemoryLayout<sockaddr_in>.size)
  42. if getsockname(socketFileDescriptor, UnsafeMutablePointer(OpaquePointer(pointer)), &len) != 0 {
  43. throw SocketError.getSockNameFailed(Errno.description())
  44. }
  45. #if os(Linux)
  46. return ntohs(addr.sin_port)
  47. #else
  48. return Int(OSHostByteOrder()) != OSLittleEndian ? addr.sin_port.littleEndian : addr.sin_port.bigEndian
  49. #endif
  50. }
  51. }
  52. public func isIPv4() throws -> Bool {
  53. var addr = sockaddr_in()
  54. return try withUnsafePointer(to: &addr) { pointer in
  55. var len = socklen_t(MemoryLayout<sockaddr_in>.size)
  56. if getsockname(socketFileDescriptor, UnsafeMutablePointer(OpaquePointer(pointer)), &len) != 0 {
  57. throw SocketError.getSockNameFailed(Errno.description())
  58. }
  59. return Int32(addr.sin_family) == AF_INET
  60. }
  61. }
  62. public func writeUTF8(_ string: String) throws {
  63. try writeUInt8(ArraySlice(string.utf8))
  64. }
  65. public func writeUInt8(_ data: [UInt8]) throws {
  66. try writeUInt8(ArraySlice(data))
  67. }
  68. public func writeUInt8(_ data: ArraySlice<UInt8>) throws {
  69. try data.withUnsafeBufferPointer {
  70. try writeBuffer($0.baseAddress!, length: data.count)
  71. }
  72. }
  73. public func writeData(_ data: NSData) throws {
  74. try writeBuffer(data.bytes, length: data.length)
  75. }
  76. public func writeData(_ data: Data) throws {
  77. try data.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) -> Void in
  78. try self.writeBuffer(pointer, length: data.count)
  79. }
  80. }
  81. private func writeBuffer(_ pointer: UnsafeRawPointer, length: Int) throws {
  82. var sent = 0
  83. while sent < length {
  84. #if os(Linux)
  85. let s = send(self.socketFileDescriptor, pointer + sent, Int(length - sent), Int32(MSG_NOSIGNAL))
  86. #else
  87. let s = write(self.socketFileDescriptor, pointer + sent, Int(length - sent))
  88. #endif
  89. if s <= 0 {
  90. throw SocketError.writeFailed(Errno.description())
  91. }
  92. sent += s
  93. }
  94. }
  95. open func read() throws -> UInt8 {
  96. var buffer = [UInt8](repeating: 0, count: 1)
  97. let next = recv(self.socketFileDescriptor as Int32, &buffer, Int(buffer.count), Int32(MSG_NOSIGNAL))
  98. if next <= 0 {
  99. throw SocketError.recvFailed(Errno.description())
  100. }
  101. return buffer[0]
  102. }
  103. private static let CR = UInt8(13)
  104. private static let NL = UInt8(10)
  105. public func readLine() throws -> String {
  106. var characters: String = ""
  107. var n: UInt8 = 0
  108. repeat {
  109. n = try self.read()
  110. if n > Socket.CR { characters.append(Character(UnicodeScalar(n))) }
  111. } while n != Socket.NL
  112. return characters
  113. }
  114. public func peername() throws -> String {
  115. var addr = sockaddr(), len: socklen_t = socklen_t(MemoryLayout<sockaddr>.size)
  116. if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
  117. throw SocketError.getPeerNameFailed(Errno.description())
  118. }
  119. var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
  120. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  121. throw SocketError.getNameInfoFailed(Errno.description())
  122. }
  123. return String(cString: hostBuffer)
  124. }
  125. public class func setNoSigPipe(_ socket: Int32) {
  126. #if os(Linux)
  127. // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
  128. // or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
  129. #else
  130. // Prevents crashes when blocking calls are pending and the app is paused ( via Home button ).
  131. var no_sig_pipe: Int32 = 1
  132. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(MemoryLayout<Int32>.size))
  133. #endif
  134. }
  135. public class func close(_ socket: Int32) {
  136. #if os(Linux)
  137. let _ = Glibc.close(socket)
  138. #else
  139. let _ = Darwin.close(socket)
  140. #endif
  141. }
  142. }
  143. public func == (socket1: Socket, socket2: Socket) -> Bool {
  144. return socket1.socketFileDescriptor == socket2.socketFileDescriptor
  145. }