Socket.swift 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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: ErrorType {
  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(AF_INET, 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))) == -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()
  46. addr.sin_family = sa_family_t(AF_INET)
  47. addr.sin_port = Socket.htonsPort(port)
  48. addr.sin_addr = in_addr(s_addr: in_addr_t(0))
  49. addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0)
  50. bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in))) }
  51. } else {
  52. }
  53. #else
  54. var bindResult: Int32 = -1
  55. if forceIPv4 {
  56. var addr = sockaddr_in(
  57. sin_len: UInt8(strideof(sockaddr_in)),
  58. sin_family: UInt8(AF_INET),
  59. sin_port: Socket.htonsPort(port),
  60. sin_addr: in_addr(s_addr: in_addr_t(0)),
  61. sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
  62. bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in))) }
  63. } else {
  64. var addr = sockaddr_in6(sin6_len:
  65. UInt8(strideof(sockaddr_in6)),
  66. sin6_family: UInt8(AF_INET6),
  67. sin6_port: Socket.htonsPort(port),
  68. sin6_flowinfo: 0,
  69. sin6_addr: in6addr_any,
  70. sin6_scope_id: 0)
  71. bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in6))) }
  72. }
  73. #endif
  74. if bindResult == -1 {
  75. let details = Socket.descriptionOfLastError()
  76. Socket.release(socketFileDescriptor)
  77. throw SocketError.BindFailed(details)
  78. }
  79. if listen(socketFileDescriptor, maxPendingConnection ) == -1 {
  80. let details = Socket.descriptionOfLastError()
  81. Socket.release(socketFileDescriptor)
  82. throw SocketError.ListenFailed(details)
  83. }
  84. return Socket(socketFileDescriptor: socketFileDescriptor)
  85. }
  86. private let socketFileDescriptor: Int32
  87. public init(socketFileDescriptor: Int32) {
  88. self.socketFileDescriptor = socketFileDescriptor
  89. }
  90. public var hashValue: Int { return Int(self.socketFileDescriptor) }
  91. public func release() {
  92. Socket.release(self.socketFileDescriptor)
  93. }
  94. public func shutdwn() {
  95. Socket.shutdwn(self.socketFileDescriptor)
  96. }
  97. public func acceptClientSocket() throws -> Socket {
  98. var addr = sockaddr()
  99. var len: socklen_t = 0
  100. let clientSocket = accept(self.socketFileDescriptor, &addr, &len)
  101. if clientSocket == -1 {
  102. throw SocketError.AcceptFailed(Socket.descriptionOfLastError())
  103. }
  104. Socket.setNoSigPipe(clientSocket)
  105. return Socket(socketFileDescriptor: clientSocket)
  106. }
  107. public func writeUTF8(string: String) throws {
  108. try writeUInt8(ArraySlice(string.utf8))
  109. }
  110. public func writeUInt8(data: [UInt8]) throws {
  111. try writeUInt8(ArraySlice(data))
  112. }
  113. public func writeUInt8(data: ArraySlice<UInt8>) throws {
  114. try data.withUnsafeBufferPointer {
  115. var sent = 0
  116. while sent < data.count {
  117. #if os(Linux)
  118. let s = send(self.socketFileDescriptor, $0.baseAddress + sent, Int(data.count - sent), Int32(MSG_NOSIGNAL))
  119. #else
  120. let s = write(self.socketFileDescriptor, $0.baseAddress + sent, Int(data.count - sent))
  121. #endif
  122. if s <= 0 {
  123. throw SocketError.WriteFailed(Socket.descriptionOfLastError())
  124. }
  125. sent += s
  126. }
  127. }
  128. }
  129. public func read() throws -> UInt8 {
  130. var buffer = [UInt8](count: 1, repeatedValue: 0)
  131. let next = recv(self.socketFileDescriptor as Int32, &buffer, Int(buffer.count), 0)
  132. if next <= 0 {
  133. throw SocketError.RecvFailed(Socket.descriptionOfLastError())
  134. }
  135. return buffer[0]
  136. }
  137. private static let CR = UInt8(13)
  138. private static let NL = UInt8(10)
  139. public func readLine() throws -> String {
  140. var characters: String = ""
  141. var n: UInt8 = 0
  142. repeat {
  143. n = try self.read()
  144. if n > Socket.CR { characters.append(Character(UnicodeScalar(n))) }
  145. } while n != Socket.NL
  146. return characters
  147. }
  148. public func peername() throws -> String {
  149. var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr))
  150. if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
  151. throw SocketError.GetPeerNameFailed(Socket.descriptionOfLastError())
  152. }
  153. var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
  154. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  155. throw SocketError.GetNameInfoFailed(Socket.descriptionOfLastError())
  156. }
  157. guard let name = String.fromCString(hostBuffer) else {
  158. throw SocketError.ConvertingPeerNameFailed
  159. }
  160. return name
  161. }
  162. private class func descriptionOfLastError() -> String {
  163. return String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)"
  164. }
  165. private class func setNoSigPipe(socket: Int32) {
  166. #if os(Linux)
  167. // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
  168. // or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
  169. #else
  170. // Prevents crashes when blocking calls are pending and the app is paused ( via Home button ).
  171. var no_sig_pipe: Int32 = 1
  172. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)))
  173. #endif
  174. }
  175. private class func shutdwn(socket: Int32) {
  176. #if os(Linux)
  177. shutdown(socket, Int32(SHUT_RDWR))
  178. #else
  179. Darwin.shutdown(socket, SHUT_RDWR)
  180. #endif
  181. }
  182. private class func release(socket: Int32) {
  183. #if os(Linux)
  184. shutdown(socket, Int32(SHUT_RDWR))
  185. #else
  186. Darwin.shutdown(socket, SHUT_RDWR)
  187. #endif
  188. close(socket)
  189. }
  190. private class func htonsPort(port: in_port_t) -> in_port_t {
  191. #if os(Linux)
  192. return htons(port)
  193. #else
  194. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  195. return isLittleEndian ? _OSSwapInt16(port) : port
  196. #endif
  197. }
  198. }
  199. public func ==(socket1: Socket, socket2: Socket) -> Bool {
  200. return socket1.socketFileDescriptor == socket2.socketFileDescriptor
  201. }