Socket.swift 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. }
  25. public class Socket: Hashable, Equatable {
  26. public class func tcpSocketForListen(_ port: in_port_t, forceIPv4: Bool = false, maxPendingConnection: Int32 = SOMAXCONN) throws -> Socket {
  27. #if os(Linux)
  28. let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, Int32(SOCK_STREAM.rawValue), 0)
  29. #else
  30. let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0)
  31. #endif
  32. if socketFileDescriptor == -1 {
  33. throw SocketError.socketCreationFailed(Socket.descriptionOfLastError())
  34. }
  35. var value: Int32 = 1
  36. if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32.self))) == -1 {
  37. let details = Socket.descriptionOfLastError()
  38. Socket.release(socketFileDescriptor)
  39. throw SocketError.socketSettingReUseAddrFailed(details)
  40. }
  41. Socket.setNoSigPipe(socketFileDescriptor)
  42. #if os(Linux)
  43. var bindResult: Int32 = -1
  44. if forceIPv4 {
  45. var addr = sockaddr_in(sin_family: sa_family_t(AF_INET),
  46. sin_port: Socket.htonsPort(port),
  47. sin_addr: in_addr(s_addr: in_addr_t(0)),
  48. sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
  49. bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in))) }
  50. } else {
  51. var addr = sockaddr_in6(sin6_family: sa_family_t(AF_INET6),
  52. sin6_port: Socket.htonsPort(port),
  53. sin6_flowinfo: 0,
  54. sin6_addr: in6addr_any,
  55. sin6_scope_id: 0)
  56. bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in6))) }
  57. }
  58. #else
  59. var bindResult: Int32 = -1
  60. if forceIPv4 {
  61. var addr = sockaddr_in(sin_len: UInt8(strideof(sockaddr_in.self)),
  62. sin_family: UInt8(AF_INET),
  63. sin_port: Socket.htonsPort(port),
  64. sin_addr: in_addr(s_addr: in_addr_t(0)),
  65. sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
  66. bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in.self))) }
  67. } else {
  68. // “Apple recommends always making an IPv6 socket to listen on. The OS will automatically
  69. // “downgrade” it to an IPv4 socket if necessary, so there is no need to listen on two different sockets”.
  70. var addr = sockaddr_in6(sin6_len: UInt8(strideof(sockaddr_in6.self)),
  71. sin6_family: UInt8(AF_INET6),
  72. sin6_port: Socket.htonsPort(port),
  73. sin6_flowinfo: 0,
  74. sin6_addr: in6addr_any,
  75. sin6_scope_id: 0)
  76. bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in6.self))) }
  77. }
  78. #endif
  79. if bindResult == -1 {
  80. let details = Socket.descriptionOfLastError()
  81. Socket.release(socketFileDescriptor)
  82. throw SocketError.bindFailed(details)
  83. }
  84. if listen(socketFileDescriptor, maxPendingConnection ) == -1 {
  85. let details = Socket.descriptionOfLastError()
  86. Socket.release(socketFileDescriptor)
  87. throw SocketError.listenFailed(details)
  88. }
  89. return Socket(socketFileDescriptor: socketFileDescriptor)
  90. }
  91. internal let socketFileDescriptor: Int32
  92. public init(socketFileDescriptor: Int32) {
  93. self.socketFileDescriptor = socketFileDescriptor
  94. }
  95. public var hashValue: Int { return Int(self.socketFileDescriptor) }
  96. public func release() {
  97. Socket.release(self.socketFileDescriptor)
  98. }
  99. public func shutdwn() {
  100. Socket.shutdwn(self.socketFileDescriptor)
  101. }
  102. public func acceptClientSocket() throws -> Socket {
  103. var addr = sockaddr()
  104. var len: socklen_t = 0
  105. let clientSocket = accept(self.socketFileDescriptor, &addr, &len)
  106. if clientSocket == -1 {
  107. throw SocketError.acceptFailed(Socket.descriptionOfLastError())
  108. }
  109. Socket.setNoSigPipe(clientSocket)
  110. return Socket(socketFileDescriptor: clientSocket)
  111. }
  112. public func writeUTF8(_ string: String) throws {
  113. try writeUInt8(ArraySlice(string.utf8))
  114. }
  115. public func writeUInt8(_ data: [UInt8]) throws {
  116. try writeUInt8(ArraySlice(data))
  117. }
  118. public func writeUInt8(_ data: ArraySlice<UInt8>) throws {
  119. try data.withUnsafeBufferPointer {
  120. guard let baseAddress = $0.baseAddress else {
  121. throw SocketError.writeFailed("The base address of data slice is nil.")
  122. }
  123. var sent = 0
  124. while sent < data.count {
  125. #if os(Linux)
  126. let s = send(self.socketFileDescriptor, baseAddress + sent, Int(data.count - sent), Int32(MSG_NOSIGNAL))
  127. #else
  128. let s = write(self.socketFileDescriptor, baseAddress + sent, Int(data.count - sent))
  129. #endif
  130. if s <= 0 {
  131. throw SocketError.writeFailed(Socket.descriptionOfLastError())
  132. }
  133. sent += s
  134. }
  135. }
  136. }
  137. public func read() throws -> UInt8 {
  138. var buffer = [UInt8](repeating: 0, count: 1)
  139. let next = recv(self.socketFileDescriptor as Int32, &buffer, Int(buffer.count), 0)
  140. if next <= 0 {
  141. throw SocketError.recvFailed(Socket.descriptionOfLastError())
  142. }
  143. return buffer[0]
  144. }
  145. private static let CR = UInt8(13)
  146. private static let NL = UInt8(10)
  147. public func readLine() throws -> String {
  148. var characters: String = ""
  149. var n: UInt8 = 0
  150. repeat {
  151. n = try self.read()
  152. if n > Socket.CR { characters.append(Character(UnicodeScalar(n))) }
  153. } while n != Socket.NL
  154. return characters
  155. }
  156. public func peername() throws -> String {
  157. var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr.self))
  158. if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
  159. throw SocketError.getPeerNameFailed(Socket.descriptionOfLastError())
  160. }
  161. var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
  162. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  163. throw SocketError.getNameInfoFailed(Socket.descriptionOfLastError())
  164. }
  165. return String(cString: hostBuffer)
  166. }
  167. private class func descriptionOfLastError() -> String {
  168. return String(cString: UnsafePointer(strerror(errno))) ?? "Error: \(errno)"
  169. }
  170. private class func setNoSigPipe(_ socket: Int32) {
  171. #if os(Linux)
  172. // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
  173. // or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
  174. #else
  175. // Prevents crashes when blocking calls are pending and the app is paused ( via Home button ).
  176. var no_sig_pipe: Int32 = 1
  177. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32.self)))
  178. #endif
  179. }
  180. private class func shutdwn(_ socket: Int32) {
  181. #if os(Linux)
  182. shutdown(socket, Int32(SHUT_RDWR))
  183. #else
  184. let _ = Darwin.shutdown(socket, SHUT_RDWR)
  185. #endif
  186. }
  187. private class func release(_ socket: Int32) {
  188. #if os(Linux)
  189. shutdown(socket, Int32(SHUT_RDWR))
  190. close(socket)
  191. #else
  192. if Darwin.shutdown(socket, SHUT_RDWR) != -1 {
  193. // If you close socket which was already closed it produces exception visible in TestFlight's crash log.
  194. // This is easily can be fixed by checking result on shutdown function != -1.
  195. close(socket)
  196. }
  197. #endif
  198. }
  199. private class func htonsPort(_ port: in_port_t) -> in_port_t {
  200. #if os(Linux)
  201. return htons(port)
  202. #else
  203. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  204. return isLittleEndian ? _OSSwapInt16(port) : port
  205. #endif
  206. }
  207. }
  208. public func ==(socket1: Socket, socket2: Socket) -> Bool {
  209. return socket1.socketFileDescriptor == socket2.socketFileDescriptor
  210. }