Socket.swift 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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 GetNameInfoFailed(String?)
  16. case AcceptFailed(String?)
  17. }
  18. let maxPendingConnection: Int32 = 20
  19. struct Socket {
  20. static func tcpForListen(port: in_port_t = 8080) throws -> CInt {
  21. let s = socket(AF_INET, SOCK_STREAM, 0)
  22. if s == -1 {
  23. throw SocketError.SocketInitializationFailed(String.fromCString(UnsafePointer(strerror(errno))))
  24. }
  25. var value: Int32 = 1
  26. if setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) == -1 {
  27. let details = String.fromCString(UnsafePointer(strerror(errno)))
  28. release(s)
  29. throw SocketError.SocketOptionInitializationFailed(details)
  30. }
  31. nosigpipe(s)
  32. var addr = sockaddr_in(sin_len: __uint8_t(sizeof(sockaddr_in)),
  33. sin_family: sa_family_t(AF_INET),
  34. sin_port: port_htons(port),
  35. sin_addr: in_addr(s_addr: inet_addr("0.0.0.0")),
  36. sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
  37. 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))
  38. memcpy(&sock_addr, &addr, Int(sizeof(sockaddr_in)))
  39. if bind(s, &sock_addr, socklen_t(sizeof(sockaddr_in))) == -1 {
  40. let details = String.fromCString(UnsafePointer(strerror(errno)))
  41. release(s)
  42. throw SocketError.BindFailed(details)
  43. }
  44. if listen(s, maxPendingConnection ) == -1 {
  45. let details = String.fromCString(UnsafePointer(strerror(errno)))
  46. release(s)
  47. throw SocketError.ListenFailed(details)
  48. }
  49. return s
  50. }
  51. static func writeUTF8(socket: CInt, string: String) throws {
  52. if let nsdata = string.dataUsingEncoding(NSUTF8StringEncoding) {
  53. try writeData(socket, data: nsdata)
  54. } else {
  55. throw SocketError.WriteFailed("dataUsingEncoding(NSUTF8StringEncoding) failed")
  56. }
  57. }
  58. static func writeASCII(socket: CInt, string: String) throws {
  59. if let nsdata = string.dataUsingEncoding(NSASCIIStringEncoding) {
  60. try writeData(socket, data: nsdata)
  61. } else {
  62. throw SocketError.WriteFailed("dataUsingEncoding(NSASCIIStringEncoding) failed")
  63. }
  64. }
  65. static func writeData(socket: CInt, data: NSData) throws {
  66. var sent = 0
  67. let unsafePointer = UnsafePointer<UInt8>(data.bytes)
  68. while sent < data.length {
  69. let s = write(socket, unsafePointer + sent, Int(data.length - sent))
  70. if s <= 0 {
  71. throw SocketError.WriteFailed(String.fromCString(UnsafePointer(strerror(errno))))
  72. }
  73. sent += s
  74. }
  75. }
  76. static func acceptClientSocket(socket: CInt) throws -> CInt {
  77. 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))
  78. var len: socklen_t = 0
  79. let clientSocket = accept(socket, &addr, &len)
  80. if clientSocket == -1 {
  81. throw SocketError.AcceptFailed(String.fromCString(UnsafePointer(strerror(errno))))
  82. }
  83. Socket.nosigpipe(clientSocket)
  84. return clientSocket
  85. }
  86. static func nosigpipe(socket: CInt) {
  87. // prevents crashes when blocking calls are pending and the app is paused ( via Home button )
  88. var no_sig_pipe: Int32 = 1;
  89. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)));
  90. }
  91. static func port_htons(port: in_port_t) -> in_port_t {
  92. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  93. return isLittleEndian ? _OSSwapInt16(port) : port
  94. }
  95. static func release(socket: CInt) {
  96. shutdown(socket, SHUT_RDWR)
  97. close(socket)
  98. }
  99. static func peername(socket: CInt) throws -> String? {
  100. var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr))
  101. if getpeername(socket, &addr, &len) != 0 {
  102. throw SocketError.GetPeerNameFailed(String.fromCString(UnsafePointer(strerror(errno))))
  103. }
  104. var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
  105. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  106. throw SocketError.GetNameInfoFailed(String.fromCString(UnsafePointer(strerror(errno))))
  107. }
  108. return String.fromCString(hostBuffer)
  109. }
  110. }