Socket.swift 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //
  2. // Socket.swift
  3. // Swifter
  4. // Copyright (c) 2014 Damian Kołakowski. All rights reserved.
  5. //
  6. import Foundation
  7. /* Low level routines for POSIX sockets */
  8. enum SocketError: ErrorType {
  9. case SocketInitializationFailed
  10. case SocketOptionInitializationFailed
  11. case BindFailed
  12. case ListenFailed
  13. case WriteFailed
  14. case PeerNameFailed
  15. case NameInfoFailed
  16. case AcceptFailed
  17. var message: String {
  18. switch self {
  19. case .SocketInitializationFailed:
  20. return "socket(...) failed"
  21. case .SocketOptionInitializationFailed:
  22. return "setsockopt(...) failed."
  23. case .BindFailed:
  24. return "bind(...) failed."
  25. case .ListenFailed:
  26. return "listen(...) failed."
  27. case .WriteFailed:
  28. return "write(...) failed"
  29. case .PeerNameFailed:
  30. return "getpeername(...) failed"
  31. case .NameInfoFailed:
  32. return "getnameinfo(...) failed"
  33. case .AcceptFailed:
  34. return "accept(...) failed."
  35. }
  36. }
  37. }
  38. let maxPendingConnection: Int32 = 20
  39. struct Socket {
  40. static func tcpForListen(port: in_port_t = 8080) throws -> CInt {
  41. let s = socket(AF_INET, SOCK_STREAM, 0)
  42. if ( s == -1 ) {
  43. throw SocketError.SocketInitializationFailed
  44. }
  45. var value: Int32 = 1;
  46. if ( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) == -1 ) {
  47. release(s)
  48. throw SocketError.SocketOptionInitializationFailed
  49. }
  50. nosigpipe(s)
  51. var addr = sockaddr_in(sin_len: __uint8_t(sizeof(sockaddr_in)),
  52. sin_family: sa_family_t(AF_INET),
  53. sin_port: port_htons(port),
  54. sin_addr: in_addr(s_addr: inet_addr("0.0.0.0")),
  55. sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
  56. 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))
  57. memcpy(&sock_addr, &addr, Int(sizeof(sockaddr_in)))
  58. if ( bind(s, &sock_addr, socklen_t(sizeof(sockaddr_in))) == -1 ) {
  59. release(s)
  60. throw SocketError.BindFailed
  61. }
  62. if ( listen(s, maxPendingConnection ) == -1 ) {
  63. release(s)
  64. throw SocketError.ListenFailed
  65. }
  66. return s
  67. }
  68. static func writeUTF8(socket: CInt, string: String) throws {
  69. if let nsdata = string.dataUsingEncoding(NSUTF8StringEncoding) {
  70. do {
  71. try writeData(socket, data: nsdata)
  72. } catch {
  73. throw error
  74. }
  75. }
  76. }
  77. static func writeASCII(socket: CInt, string: String) throws {
  78. if let nsdata = string.dataUsingEncoding(NSASCIIStringEncoding) {
  79. do {
  80. try writeData(socket, data: nsdata)
  81. } catch {
  82. throw error
  83. }
  84. }
  85. }
  86. static func writeData(socket: CInt, data: NSData) throws {
  87. var sent = 0
  88. let unsafePointer = UnsafePointer<UInt8>(data.bytes)
  89. while ( sent < data.length ) {
  90. let s = write(socket, unsafePointer + sent, Int(data.length - sent))
  91. if ( s <= 0 ) {
  92. throw SocketError.WriteFailed
  93. }
  94. sent += s
  95. }
  96. }
  97. static func acceptClientSocket(socket: CInt) throws -> CInt {
  98. 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))
  99. var len: socklen_t = 0
  100. let clientSocket = accept(socket, &addr, &len)
  101. if ( clientSocket == -1 ) {
  102. throw SocketError.AcceptFailed
  103. }
  104. Socket.nosigpipe(clientSocket)
  105. return clientSocket
  106. }
  107. static func nosigpipe(socket: CInt) {
  108. // prevents crashes when blocking calls are pending and the app is paused ( via Home button )
  109. var no_sig_pipe: Int32 = 1;
  110. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)));
  111. }
  112. static func port_htons(port: in_port_t) -> in_port_t {
  113. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  114. return isLittleEndian ? _OSSwapInt16(port) : port
  115. }
  116. static func release(socket: CInt) {
  117. shutdown(socket, SHUT_RDWR)
  118. close(socket)
  119. }
  120. static func peername(socket: CInt) throws -> String? {
  121. var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr))
  122. if getpeername(socket, &addr, &len) != 0 {
  123. throw SocketError.PeerNameFailed
  124. }
  125. var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
  126. if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
  127. throw SocketError.NameInfoFailed
  128. }
  129. return String.fromCString(hostBuffer)
  130. }
  131. }