I have spend quite some time now to find out how exactly to do socket programming in Swift (Xcode 6.1). There are a few examples out there, but most of them no longer work for the latest release of Swift.
Finally I came up with the following (see below). That seems to work, but I am not 100% certain that it is fully correct. Maybe some of you can have a look at it and see if I made any errors that might cause future (i.e. currently under the hood) problems.
The calls to "log...." refer to a self made logging facility, but that should be clear enough I think.
Any suggestions on how to improve this are welcome.
var status: Int32 = 0
// Protocol configuration
var hints = addrinfo(
ai_flags: AI_PASSIVE, // Assign the address of my local host to the socket structures
ai_family: AF_UNSPEC, // Either IPv4 or IPv6
ai_socktype: SOCK_STREAM, // TCP
ai_protocol: 0,
ai_addrlen: 0,
ai_canonname: UnsafeMutablePointer<Int8>.null(),
ai_addr: UnsafeMutablePointer<sockaddr>.null(),
ai_next: UnsafeMutablePointer<addrinfo>.null())
// For the result from the getaddrinfo
var servinfo = UnsafeMutablePointer<addrinfo>.null()
// Get the info we need to create our socket descriptor
status = getaddrinfo(UnsafePointer<Int8>.null(), ap_servicePortNumber, &hints, &servinfo)
// Cop out if there is an error
if status != 0 { return }
// Print a list of the found IP addresses
if ap_applicationInDebugMode {
var info = servinfo
while info != UnsafeMutablePointer<addrinfo>.null() {
// Check for IPv4
if info.memory.ai_family == AF_INET {
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
info.memory.ai_family,
info.memory.ai_addr,
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
let addressStr = String.fromCString(&ipAddressString)
var message = addressStr == nil ? "No IPv4 address found" : "IPv4 address: " + addressStr!
log.atLevelDebug(source: SOURCE, object: nil, message: message)
} else { // Should be IPv6
var ipAddressString = [CChar](count:Int(INET6_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
info.memory.ai_family,
info.memory.ai_addr,
&ipAddressString,
socklen_t(INET6_ADDRSTRLEN))
let addressStr = String.fromCString(&ipAddressString)
var message = addressStr == nil ? "No IPv6 address found" : "IPv6 address: " + addressStr!
log.atLevelDebug(source: SOURCE, object: nil, message: message)
}
info = info.memory.ai_next
}
}
// Get the socket descriptor, use the results from the getaddrinfo call earlier
var socketDescriptor = socket(servinfo.memory.ai_family, servinfo.memory.ai_socktype, servinfo.memory.ai_protocol);
log.atLevelDebug(source: SOURCE, object: nil, message: "Socket value: " + socketDescriptor.description)
// Since we will be listening, bind the socket descriptor to our socket
status = bind(socketDescriptor, servinfo.memory.ai_addr, servinfo.memory.ai_addrlen);
log.atLevelDebug(source: SOURCE, object: nil, message: "Status from binding: " + status.description)
// Cop out if there is an error
// PS: Need to handle "in use" errors
if status != 0 {
let message = "Binding error, status = " + status.description + ", error = " + errno.description
log.atLevelEmergency(source: SOURCE, object: nil, message: message)
setApplicationError(ErrorCode.initPortForListeningBindingError, message)
return
}
// Don't need this anymore
freeaddrinfo(servinfo)