-
-
Save hotpaw2/298114cb91231d79a1502317e1a5be10 to your computer and use it in GitHub Desktop.
A minimal implementation of a Posix UDP server in Swift.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// receive packets via UPD in Swift | |
// Original: https://gist.github.com/NeoTeo/b6195efb779d925fd7b8 | |
// server only converted to Swift 4 2018-02-24 by [email protected] | |
// | |
// swiftc udp_receive.swift -o udp_receive | |
// | |
import Foundation | |
let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian | |
let htons = isLittleEndian ? _OSSwapInt16 : { $0 } | |
let INETADDRESS_ANY = in_addr(s_addr: 0) | |
let port : UInt16 = 50037 | |
let ip_string : String = "127.0.0.1" | |
var sockAddress = sockaddr_in( | |
sin_len: UInt8(MemoryLayout<sockaddr_in>.size), | |
sin_family: sa_family_t(AF_INET), | |
sin_port: htons( port ), | |
sin_addr: in_addr(s_addr: 0), | |
sin_zero: ( 0, 0, 0, 0, 0, 0, 0, 0 ) | |
) | |
_ = ip_string.withCString( { cs in | |
inet_pton(AF_INET, | |
cs, | |
&sockAddress.sin_addr ) } ) | |
var responseSource: DispatchSourceRead? | |
func receiver() -> DispatchSourceRead? { | |
if #available(OSX 10.10, *) { | |
/* | |
1) Create a socket. | |
2) Bind the socket. | |
3) In a loop/separate thread/event listen for incoming packets. | |
*/ | |
let sockFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) | |
print("sockFd = \(sockFd)") | |
guard sockFd >= 0 else { | |
let errmsg = String(describing:strerror(errno)) | |
print("Error: Could not create socket. \(errmsg)") | |
return nil | |
} | |
let socketAddressLength = socklen_t( MemoryLayout<sockaddr>.size ) | |
// Bind socket | |
let bindSuccess = withUnsafePointer( | |
to: &sockAddress, { | |
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) { | |
zeroSockAddress in bind( sockFd, | |
zeroSockAddress, | |
socklen_t( socketAddressLength ) | |
) | |
} | |
} | |
) | |
guard bindSuccess == 0 else { | |
let errmsg = String(describing:strerror(errno)) | |
print("Error: Could not bind socket! \(errmsg)") | |
exit(-1) | |
} | |
// Create a GCD thread to listen for network events. | |
let queue = DispatchQueue.global() | |
let newResponseSource : DispatchSourceRead? | |
= DispatchSource.makeReadSource(fileDescriptor: Int32(sockFd), | |
queue: queue) | |
if newResponseSource == nil { | |
let errmsg = String(describing:strerror(errno)) | |
print("dispatch_source_create failed. \(errmsg)") | |
close(sockFd) | |
exit(-1) | |
} | |
// Register the event handler for cancellation. | |
newResponseSource!.setCancelHandler(handler: { | |
let errmsg = String(describing:strerror(errno)) | |
print("Cancel handler \(errmsg)") | |
close(sockFd) | |
exit(-1) | |
}) | |
// Register the event handler for incoming packets. | |
newResponseSource!.setEventHandler(handler: { | |
guard let source = responseSource else { return } | |
var socketAddress = sockaddr_storage() | |
var socketStorageLength = socklen_t( | |
MemoryLayout<sockaddr_storage>.size | |
) | |
let response = [UInt8](repeating: 0, count: 4096) | |
let UDPSocket | |
= Int32( (source as! DispatchSourceFileSystemObject).handle ) | |
let bytesRead = withUnsafeMutablePointer(to: &socketAddress) { | |
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) | |
{ | |
zeroSockAddress in | |
recvfrom(UDPSocket, | |
UnsafeMutableRawPointer(mutating: response), | |
response.count, | |
0, | |
zeroSockAddress, | |
&socketStorageLength ) | |
} | |
} | |
let dataRead = response[ 0 ..< bytesRead ] | |
print("read \(bytesRead) bytes: \(dataRead)") | |
if let dataString = String(bytes: dataRead, | |
encoding: | |
String.Encoding.utf8 | |
) { | |
print("The message was: \(dataString)") | |
} | |
} ) | |
// dispatch_resume(newResponseSource) | |
newResponseSource!.resume() | |
return newResponseSource | |
} else { return nil } // wrong OS | |
} | |
print("Receiver listening...") | |
responseSource = receiver() | |
RunLoop.main.run() | |
// eof |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment