Socket.swift 6.0 KB

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