Socket.swift 8.8 KB

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