Socket.swift 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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 code = errno
  12. return NSError.errorWithDomain("SOCKET", code: Int(code), userInfo:
  13. [NSLocalizedFailureReasonErrorKey : reason, NSLocalizedDescriptionKey : String.fromCString(strerror(code))])
  14. }
  15. static func tcpForListen(port: in_port_t = 8080, error:NSErrorPointer = nil) -> CInt? {
  16. let s = socket(AF_INET, SOCK_STREAM, 0)
  17. if ( s == -1 ) {
  18. if error { error.memory = socketLastError("socket(...) failed.") }
  19. return nil
  20. }
  21. var value: Int32 = 1;
  22. if ( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) == -1 ) {
  23. release(s)
  24. if error { error.memory = socketLastError("setsockopt(...) failed.") }
  25. return nil
  26. }
  27. nosigpipe(s)
  28. // Can't find htonl(...) function in Swift runtime so port value will be diffrent.
  29. var addr = sockaddr_in(sin_len: __uint8_t(sizeof(sockaddr_in)), sin_family: sa_family_t(AF_INET),
  30. sin_port: port, sin_addr: in_addr(s_addr: inet_addr("0.0.0.0")), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
  31. 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))
  32. memcpy(&sock_addr, &addr, UInt(sizeof(sockaddr_in)))
  33. if ( bind(s, &sock_addr, socklen_t(sizeof(sockaddr_in))) == -1 ) {
  34. release(s)
  35. if error { error.memory = socketLastError("bind(...) failed.") }
  36. return nil
  37. }
  38. if ( listen(s, 20 /* max pending connection */ ) == -1 ) {
  39. release(s)
  40. if error { error.memory = socketLastError("listen(...) failed.") }
  41. return nil
  42. }
  43. return s
  44. }
  45. static func writeStringUTF8(socket: CInt, string: String, error:NSErrorPointer = nil) -> Bool {
  46. var sent = 0;
  47. let nsdata = string.bridgeToObjectiveC().dataUsingEncoding(NSUTF8StringEncoding)
  48. let unsafePointer = UnsafePointer<UInt8>(nsdata.bytes)
  49. while ( sent < nsdata.length ) {
  50. let s = write(socket, unsafePointer + sent, UInt(nsdata.length - sent))
  51. if ( s <= 0 ) {
  52. if error { error.memory = socketLastError("write(\(string)) failed.") }
  53. return false
  54. }
  55. sent += s
  56. }
  57. return true
  58. }
  59. static func acceptClientSocket(socket: CInt, error:NSErrorPointer = nil) -> CInt? {
  60. 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
  61. let clientSocket = accept(socket, &addr, &len)
  62. if ( clientSocket != -1 ) {
  63. Socket.nosigpipe(clientSocket)
  64. return clientSocket
  65. }
  66. if error { error.memory = socketLastError("accept(...) failed.") }
  67. return nil
  68. }
  69. static func nosigpipe(socket: CInt) {
  70. // prevents crashes when blocking calls are pending and the app is paused ( via Home button )
  71. var no_sig_pipe: Int32 = 1;
  72. setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32)));
  73. }
  74. static func release(socket: CInt) {
  75. shutdown(socket, SHUT_RDWR)
  76. close(socket)
  77. }
  78. }