Socket.swift 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. //
  2. // Socket.swift
  3. // Swifter
  4. // Copyright (c) 2015 Damian Kołakowski. All rights reserved.
  5. //
  6. import Foundation
  7. /* Low level routines for POSIX sockets */
  8. enum SocketError: ErrorType {
  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. }
  20. public class Socket : Hashable {
  21. public class func tcpSocketForListen(port: in_port_t = 8080, maxPendingConnection: Int32 = SOMAXCONN) throws -> Socket {
  22. let socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)
  23. if socketFileDescriptor == -1 {
  24. throw SocketError.SocketCreationFailed(Socket.descriptionOfLastError())
  25. }
  26. var value: Int32 = 1
  27. if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) == -1 {
  28. let details = Socket.descriptionOfLastError()
  29. Socket.release(socketFileDescriptor)
  30. throw SocketError.SocketSettingReUseAddrFailed(details)
  31. }
  32. Socket.setNoSigPipe(socketFileDescriptor)
  33. var addr = sockaddr_in(
  34. sin_len: __uint8_t(sizeof(sockaddr_in)),
  35. sin_family: sa_family_t(AF_INET),
  36. sin_port: Socket.htonsPort(port),
  37. sin_addr: in_addr(s_addr: inet_addr("0.0.0.0")),
  38. sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
  39. var sock_addr = sockaddr(sa_len: 0, sa_family: 0, sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
  40. memcpy(&sock_addr, &addr, Int(sizeof(sockaddr_in)))
  41. if bind(socketFileDescriptor, &sock_addr, socklen_t(sizeof(sockaddr_in))) == -1 {
  42. let details = Socket.descriptionOfLastError()
  43. Socket.release(socketFileDescriptor)
  44. throw SocketError.BindFailed(details)
  45. }
  46. if listen(socketFileDescriptor, maxPendingConnection ) == -1 {
  47. let details = Socket.descriptionOfLastError()
  48. Socket.release(socketFileDescriptor)
  49. throw SocketError.ListenFailed(details)
  50. }
  51. return Socket(socketFileDescriptor: socketFileDescriptor)
  52. }
  53. private let socketFileDescriptor: CInt
  54. init(socketFileDescriptor: CInt) {
  55. self.socketFileDescriptor = socketFileDescriptor
  56. }
  57. public var hashValue: Int { return Int(self.socketFileDescriptor) }
  58. public func release() {
  59. Socket.release(self.socketFileDescriptor)
  60. }
  61. public func acceptClientSocket() throws -> Socket {
  62. var addr = sockaddr(sa_len: 0, sa_family: 0, sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
  63. var len: socklen_t = 0
  64. let clientSocket = accept(self.socketFileDescriptor, &addr, &len)
  65. if clientSocket == -1 {
  66. throw SocketError.AcceptFailed(Socket.descriptionOfLastError())
  67. }
  68. Socket.setNoSigPipe(clientSocket)
  69. return Socket(socketFileDescriptor: clientSocket)
  70. }
  71. public func writeUTF8(string: String) throws {
  72. try self.writeString(string, withEncoding: NSUTF8StringEncoding)
  73. }
  74. public func writeASCII(string: String) throws {
  75. try self.writeString(string, withEncoding: NSASCIIStringEncoding)
  76. }
  77. public func writeString(string: String, withEncoding encoding: NSStringEncoding) throws {
  78. if let nsdata = string.dataUsingEncoding(encoding) {
  79. try self.writeData(nsdata)
  80. } else {
  81. throw SocketError.WriteFailed("dataUsingEncoding(\(encoding)) failed")
  82. }
  83. }
  84. public func writeData(data: NSData) throws {
  85. var sent = 0
  86. let unsafePointer = UnsafePointer<UInt8>(data.bytes)
  87. while sent < data.length {
  88. let s = write(self.socketFileDescriptor, unsafePointer + sent, Int(data.length - sent))
  89. if s <= 0 {
  90. throw SocketError.WriteFailed(Socket.descriptionOfLastError())
  91. }
  92. sent += s
  93. }
  94. }
  95. public func read() -> Int {
  96. var buffer = [UInt8](count: 1, repeatedValue: 0);
  97. let next = recv(self.socketFileDescriptor as Int32, &buffer, Int(buffer.count), 0)
  98. if next <= 0 {
  99. return next
  100. }
  101. return Int(buffer[0])
  102. }
  103. public func readLine() throws -> String {
  104. var characters: String = ""
  105. var n = 0
  106. repeat {
  107. n = self.read()
  108. if ( n > 13 /* CR */ ) { characters.append(Character(UnicodeScalar(n))) }
  109. } while n > 0 && n != 10 /* NL */
  110. if n == -1 {
  111. throw SocketError.RecvFailed(Socket.descriptionOfLastError())
  112. }
  113. return characters
  114. }
  115. public func peername() throws -> String {
  116. var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr))
  117. if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
  118. throw SocketError.GetPeerNameFailed(Socket.descriptionOfLastError())
  119. }
  120. var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
  121. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  122. throw SocketError.GetNameInfoFailed(Socket.descriptionOfLastError())
  123. }
  124. guard let name = String.fromCString(hostBuffer) else {
  125. throw SocketError.ConvertingPeerNameFailed
  126. }
  127. return name
  128. }
  129. private class func descriptionOfLastError() -> String {
  130. return String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)"
  131. }
  132. private class func setNoSigPipe(socket: CInt) {
  133. // prevents crashes when blocking calls are pending and the app is paused ( via Home button )
  134. var no_sig_pipe: Int32 = 1;
  135. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)));
  136. }
  137. private class func release(socket: CInt) {
  138. shutdown(socket, SHUT_RDWR)
  139. close(socket)
  140. }
  141. private class func htonsPort(port: in_port_t) -> in_port_t {
  142. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  143. return isLittleEndian ? _OSSwapInt16(port) : port
  144. }
  145. }
  146. public func ==(socket1: Socket, socket2: Socket) -> Bool {
  147. return socket1.hashValue == socket2.hashValue
  148. }