Socket.swift 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //
  2. // Socket.swift
  3. //
  4. // Created by Damian Kolakowski on 05/06/14.
  5. // Copyright (c) 2014 Damian Kołakowski. All rights reserved.
  6. //
  7. import Foundation
  8. /* Low level routines for POSIX sockets */
  9. struct Socket {
  10. static func socketLastError(reason:String) -> NSError {
  11. let errorCode = errno
  12. if let errorText = String.fromCString(UnsafePointer(strerror(errorCode))) {
  13. return NSError(domain: "SOCKET", code: Int(errorCode), userInfo: [NSLocalizedFailureReasonErrorKey : reason, NSLocalizedDescriptionKey : errorText])
  14. }
  15. return NSError(domain: "SOCKET", code: Int(errorCode), userInfo: nil)
  16. }
  17. static func tcpForListen(port: in_port_t = 8080, error:NSErrorPointer = nil) -> CInt? {
  18. let s = socket(AF_INET, SOCK_STREAM, 0)
  19. if ( s == -1 ) {
  20. if error != nil { error.memory = socketLastError("socket(...) failed.") }
  21. return nil
  22. }
  23. var value: Int32 = 1;
  24. if ( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) == -1 ) {
  25. release(s)
  26. if error != nil { error.memory = socketLastError("setsockopt(...) failed.") }
  27. return nil
  28. }
  29. nosigpipe(s)
  30. var addr = sockaddr_in(sin_len: __uint8_t(sizeof(sockaddr_in)), sin_family: sa_family_t(AF_INET),
  31. sin_port: port_htons(port), sin_addr: in_addr(s_addr: inet_addr("0.0.0.0")), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
  32. 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))
  33. memcpy(&sock_addr, &addr, UInt(sizeof(sockaddr_in)))
  34. if ( bind(s, &sock_addr, socklen_t(sizeof(sockaddr_in))) == -1 ) {
  35. release(s)
  36. if error != nil { error.memory = socketLastError("bind(...) failed.") }
  37. return nil
  38. }
  39. if ( listen(s, 20 /* max pending connection */ ) == -1 ) {
  40. release(s)
  41. if error != nil { error.memory = socketLastError("listen(...) failed.") }
  42. return nil
  43. }
  44. return s
  45. }
  46. static func writeStringUTF8(socket: CInt, string: String, error: NSErrorPointer = nil) -> Bool {
  47. if let nsdata = string.dataUsingEncoding(NSUTF8StringEncoding) {
  48. writeData(socket, data: nsdata, error: error)
  49. }
  50. return true
  51. }
  52. static func writeStringASCII(socket: CInt, string: String, error: NSErrorPointer = nil) -> Bool {
  53. if let nsdata = string.dataUsingEncoding(NSASCIIStringEncoding) {
  54. writeData(socket, data: nsdata, error: error)
  55. }
  56. return true
  57. }
  58. static func writeData(socket: CInt, data: NSData, error:NSErrorPointer = nil) -> Bool {
  59. var sent = 0
  60. let unsafePointer = UnsafePointer<UInt8>(data.bytes)
  61. while ( sent < data.length ) {
  62. let s = write(socket, unsafePointer + sent, UInt(data.length - sent))
  63. if ( s <= 0 ) {
  64. if error != nil { error.memory = socketLastError("write(...) failed.") }
  65. return false
  66. }
  67. sent += s
  68. }
  69. return true
  70. }
  71. static func acceptClientSocket(socket: CInt, error:NSErrorPointer = nil) -> CInt? {
  72. 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)), len: socklen_t = 0
  73. let clientSocket = accept(socket, &addr, &len)
  74. if ( clientSocket != -1 ) {
  75. Socket.nosigpipe(clientSocket)
  76. return clientSocket
  77. }
  78. if error != nil { error.memory = socketLastError("accept(...) failed.") }
  79. return nil
  80. }
  81. static func nosigpipe(socket: CInt) {
  82. // prevents crashes when blocking calls are pending and the app is paused ( via Home button )
  83. var no_sig_pipe: Int32 = 1;
  84. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)));
  85. }
  86. static func port_htons(port: in_port_t) -> in_port_t {
  87. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  88. return isLittleEndian ? _OSSwapInt16(port) : port
  89. }
  90. static func release(socket: CInt) {
  91. shutdown(socket, SHUT_RDWR)
  92. close(socket)
  93. }
  94. }