Socket.swift 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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(ConstUnsafePointer(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 { 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 { 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 { error.memory = socketLastError("bind(...) failed.") }
  37. return nil
  38. }
  39. if ( listen(s, 20 /* max pending connection */ ) == -1 ) {
  40. release(s)
  41. if error { 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. let nsdata = string.bridgeToObjectiveC().dataUsingEncoding(NSUTF8StringEncoding)
  49. let unsafePointer = ConstUnsafePointer<UInt8>(nsdata.bytes)
  50. while ( sent < nsdata.length ) {
  51. let s = write(socket, unsafePointer + sent, UInt(nsdata.length - sent))
  52. if ( s <= 0 ) {
  53. if error { error.memory = socketLastError("write(\(string)) failed.") }
  54. return false
  55. }
  56. sent += s
  57. }
  58. return true
  59. }
  60. static func acceptClientSocket(socket: CInt, error:NSErrorPointer = nil) -> CInt? {
  61. 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
  62. let clientSocket = accept(socket, &addr, &len)
  63. if ( clientSocket != -1 ) {
  64. Socket.nosigpipe(clientSocket)
  65. return clientSocket
  66. }
  67. if error { error.memory = socketLastError("accept(...) failed.") }
  68. return nil
  69. }
  70. static func nosigpipe(socket: CInt) {
  71. // prevents crashes when blocking calls are pending and the app is paused ( via Home button )
  72. var no_sig_pipe: Int32 = 1;
  73. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)));
  74. }
  75. static func port_htons(port: in_port_t) -> in_port_t {
  76. let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
  77. return isLittleEndian ? _OSSwapInt16(port) : port
  78. }
  79. static func release(socket: CInt) {
  80. shutdown(socket, SHUT_RDWR)
  81. close(socket)
  82. }
  83. }