Socket.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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.errorWithDomain("SOCKET", code: Int(errorCode), userInfo: [NSLocalizedFailureReasonErrorKey : reason, NSLocalizedDescriptionKey : errorText])
  14. }
  15. return NSError.errorWithDomain("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. var sent = 0;
  48. if let nsdata = string.dataUsingEncoding(NSUTF8StringEncoding)
  49. {
  50. let unsafePointer = UnsafePointer<UInt8>(nsdata.bytes)
  51. while ( sent < nsdata.length ) {
  52. let s = write(socket, unsafePointer + sent, UInt(nsdata.length - sent))
  53. if ( s <= 0 ) {
  54. if error != nil { error.memory = socketLastError("write(\(string)) failed.") }
  55. return false
  56. }
  57. sent += s
  58. }
  59. }
  60. return true
  61. }
  62. static func acceptClientSocket(socket: CInt, error:NSErrorPointer = nil) -> CInt? {
  63. 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
  64. let clientSocket = accept(socket, &addr, &len)
  65. if ( clientSocket != -1 ) {
  66. Socket.nosigpipe(clientSocket)
  67. return clientSocket
  68. }
  69. if error != nil { error.memory = socketLastError("accept(...) failed.") }
  70. return nil
  71. }
  72. static func nosigpipe(socket: CInt) {
  73. // prevents crashes when blocking calls are pending and the app is paused ( via Home button )
  74. var no_sig_pipe: Int32 = 1;
  75. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)));
  76. }
  77. static func port_htons(port: in_port_t) -> in_port_t {
  78. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  79. return isLittleEndian ? _OSSwapInt16(port) : port
  80. }
  81. static func release(socket: CInt) {
  82. shutdown(socket, SHUT_RDWR)
  83. close(socket)
  84. }
  85. }