Socket.swift 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //
  2. // Socket.swift
  3. // Swifter
  4. //
  5. // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. #if os(Linux)
  8. import Glibc
  9. #else
  10. import Foundation
  11. #endif
  12. /* Low level routines for POSIX sockets */
  13. public enum SocketError: Error {
  14. case socketCreationFailed(String)
  15. case socketSettingReUseAddrFailed(String)
  16. case bindFailed(String)
  17. case listenFailed(String)
  18. case writeFailed(String)
  19. case getPeerNameFailed(String)
  20. case convertingPeerNameFailed
  21. case getNameInfoFailed(String)
  22. case acceptFailed(String)
  23. case recvFailed(String)
  24. case getSockNameFailed(String)
  25. }
  26. public class Socket: Hashable, Equatable {
  27. let socketFileDescriptor: Int32
  28. public init(socketFileDescriptor: Int32) {
  29. self.socketFileDescriptor = socketFileDescriptor
  30. }
  31. deinit {
  32. shutdwn()
  33. }
  34. public var hashValue: Int { return Int(self.socketFileDescriptor) }
  35. public func release() {
  36. Socket.release(self.socketFileDescriptor)
  37. }
  38. public func shutdwn() {
  39. Socket.shutdwn(self.socketFileDescriptor)
  40. }
  41. public func port() throws -> in_port_t {
  42. var addr = sockaddr_in()
  43. let addr_copy = addr
  44. return try withUnsafePointer(to: &addr) { pointer in
  45. var len = socklen_t(MemoryLayout<sockaddr_in>.size)
  46. if getsockname(socketFileDescriptor, UnsafeMutablePointer(OpaquePointer(pointer)), &len) != 0 {
  47. throw SocketError.getSockNameFailed(Process.lastErrno)
  48. }
  49. #if os(Linux)
  50. return ntohs(addr_copy.sin_port)
  51. #else
  52. return Int(OSHostByteOrder()) != OSLittleEndian ? addr_copy.sin_port.littleEndian : addr_copy.sin_port.bigEndian
  53. #endif
  54. }
  55. }
  56. public func isIPv4() throws -> Bool {
  57. var addr = sockaddr_in()
  58. let addr_copy = addr
  59. return try withUnsafePointer(to: &addr) { pointer in
  60. var len = socklen_t(MemoryLayout<sockaddr_in>.size)
  61. if getsockname(socketFileDescriptor, UnsafeMutablePointer(OpaquePointer(pointer)), &len) != 0 {
  62. throw SocketError.getSockNameFailed(Process.lastErrno)
  63. }
  64. return Int32(addr_copy.sin_family) == AF_INET
  65. }
  66. }
  67. public func writeUTF8(_ string: String) throws {
  68. try writeUInt8(ArraySlice(string.utf8))
  69. }
  70. public func writeUInt8(_ data: [UInt8]) throws {
  71. try writeUInt8(ArraySlice(data))
  72. }
  73. public func writeUInt8(_ data: ArraySlice<UInt8>) throws {
  74. try data.withUnsafeBufferPointer {
  75. guard let baseAddress = $0.baseAddress else {
  76. throw SocketError.writeFailed("The base address of data slice is nil.")
  77. }
  78. var sent = 0
  79. while sent < data.count {
  80. #if os(Linux)
  81. let s = send(self.socketFileDescriptor, baseAddress + sent, Int(data.count - sent), Int32(MSG_NOSIGNAL))
  82. #else
  83. let s = write(self.socketFileDescriptor, baseAddress + sent, Int(data.count - sent))
  84. #endif
  85. if s <= 0 {
  86. throw SocketError.writeFailed(Process.lastErrno)
  87. }
  88. sent += s
  89. }
  90. }
  91. }
  92. public func read() throws -> UInt8 {
  93. var buffer = [UInt8](repeating: 0, count: 1)
  94. let next = recv(self.socketFileDescriptor as Int32, &buffer, Int(buffer.count), 0)
  95. if next <= 0 {
  96. throw SocketError.recvFailed(Process.lastErrno)
  97. }
  98. return buffer[0]
  99. }
  100. private static let CR = UInt8(13)
  101. private static let NL = UInt8(10)
  102. public func readLine() throws -> String {
  103. var characters: String = ""
  104. var n: UInt8 = 0
  105. repeat {
  106. n = try self.read()
  107. if n > Socket.CR { characters.append(Character(UnicodeScalar(n))) }
  108. } while n != Socket.NL
  109. return characters
  110. }
  111. public func peername() throws -> String {
  112. var addr = sockaddr(), len: socklen_t = socklen_t(MemoryLayout<sockaddr>.size)
  113. if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
  114. throw SocketError.getPeerNameFailed(Process.lastErrno)
  115. }
  116. var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
  117. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  118. throw SocketError.getNameInfoFailed(Process.lastErrno)
  119. }
  120. return String(cString: hostBuffer)
  121. }
  122. public class func setNoSigPipe(_ socket: Int32) {
  123. #if os(Linux)
  124. // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
  125. // or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
  126. #else
  127. // Prevents crashes when blocking calls are pending and the app is paused ( via Home button ).
  128. var no_sig_pipe: Int32 = 1
  129. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(MemoryLayout<Int32>.size))
  130. #endif
  131. }
  132. public class func shutdwn(_ socket: Int32) {
  133. #if os(Linux)
  134. shutdown(socket, Int32(SHUT_RDWR))
  135. #else
  136. let _ = Darwin.shutdown(socket, SHUT_RDWR)
  137. #endif
  138. }
  139. public class func release(_ socket: Int32) {
  140. #if os(Linux)
  141. shutdown(socket, Int32(SHUT_RDWR))
  142. close(socket)
  143. #else
  144. if Darwin.shutdown(socket, SHUT_RDWR) != -1 {
  145. // If you close socket which was already closed it produces exception visible in TestFlight's crash log.
  146. // This is easily can be fixed by checking result on shutdown function != -1.
  147. close(socket)
  148. }
  149. #endif
  150. }
  151. }
  152. public func ==(socket1: Socket, socket2: Socket) -> Bool {
  153. return socket1.socketFileDescriptor == socket2.socketFileDescriptor
  154. }