I've been trying to write a simple TCP/IP server in swift but I couldn't come up with a solution. I've already tried searching on both here and the rest of the web but I couldn't find something that works for the latest swift version which I am working with:
Apple Swift version 2.1 (swiftlang-700.1.101.6 clang-700.1.76)
Target: x86_64-apple-darwin14.5.0
Operating system:
Mac OS X 10.10.5 Yosemitte
The following code has been made and it's based on this one: Socket Server Example with Swift
import Foundation
var sock_fd: Int32
var server_addr_size: Int
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if sock_fd == -1 {
print("Failure: creating socket")
exit(EXIT_FAILURE)
}
server_addr_size = sizeof(sockaddr_in)
var server_addr = NSMutableData(length: server_addr_size)!
memset(UnsafeMutablePointer<Void>(server_addr.mutableBytes), 0, server_addr_size)
var addr = UnsafeMutablePointer<sockaddr_in>(server_addr.mutableBytes)
addr.memory.sin_len = __uint8_t(server_addr_size)
addr.memory.sin_family = sa_family_t(AF_INET) // chooses IPv4
addr.memory.sin_port = 12321 // chooses the port
let bind_server = bind(sock_fd, UnsafePointer<sockaddr>(server_addr.mutableBytes), socklen_t(server_addr_size))
if bind_server == -1 {
print("Failure: binding port")
exit(EXIT_FAILURE)
}
if listen(sock_fd, 5) == -1 {
print("Failure: listening")
exit(EXIT_FAILURE)
}
var client_addr = NSMutableData(length: server_addr_size)!
memset(UnsafeMutablePointer<Void>(client_addr.mutableBytes), 0, server_addr_size)
let client_fd = accept(sock_fd, UnsafeMutablePointer<sockaddr>(client_addr.mutableBytes), UnsafeMutablePointer<socklen_t>(bitPattern: server_addr_size))
if client_fd == -1 {
print("Failure: accepting connection")
exit(EXIT_FAILURE);
}
The call to accept fails as it can be seen on the output given by the mentioned code:
Failure: accepting connection
Program ended with exit code: 1
In addition to the assistance on fixing the code, I would also like to know how I could read and write to/from the connection.
Thanks,
G Oliveira
In
UnsafeMutablePointer<socklen_t>(bitPattern: server_addr_size)
you are re-interpreting an integer variable as a pointer. That makes no
sense and crashes at runtime because the contents of the variable does
not point to valid memory. The accept() function expects the address
of a variable of type socklen_t here.
There are other problems as well, e.g. the port number in the socket address must be in big-endian byte order:
server_addr.sin_port = UInt16(12321).bigEndian // chooses the port
otherwise your program listens on port 8496 instead of 12321.
Using NSMutableData is not really necessary, Since Swift 1.2 you can
create a sockaddr_in structure with all elements set to zero
simply with:
var server_addr = sockaddr_in()
and then withUnsafePointer() can be used to get an address to the structure.
If a system call fails, the global variable errno is set to a non-zero value indicating the cause of the error. perror() can be used to print the error message corresponding to errno.
You may want to set the SO_REUSEADDR socket option to avoid
an "Address is already in use" error when binding the socket, see
Uses of SO_REUSEADDR? or
Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems? for more information.
Here is a cleaned-up version of your code which works as expected
in my test:
let sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if sock_fd == -1 {
perror("Failure: creating socket")
exit(EXIT_FAILURE)
}
var sock_opt_on = Int32(1)
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt_on, socklen_t(sizeofValue(sock_opt_on)))
var server_addr = sockaddr_in()
let server_addr_size = socklen_t(sizeofValue(server_addr))
server_addr.sin_len = UInt8(server_addr_size)
server_addr.sin_family = sa_family_t(AF_INET) // chooses IPv4
server_addr.sin_port = UInt16(12321).bigEndian // chooses the port
let bind_server = withUnsafePointer(&server_addr) {
bind(sock_fd, UnsafePointer($0), server_addr_size)
}
if bind_server == -1 {
perror("Failure: binding port")
exit(EXIT_FAILURE)
}
if listen(sock_fd, 5) == -1 {
perror("Failure: listening")
exit(EXIT_FAILURE)
}
var client_addr = sockaddr_storage()
var client_addr_len = socklen_t(sizeofValue(client_addr))
let client_fd = withUnsafeMutablePointer(&client_addr) {
accept(sock_fd, UnsafeMutablePointer($0), &client_addr_len)
}
if client_fd == -1 {
perror("Failure: accepting connection")
exit(EXIT_FAILURE);
}
print("connection accepted")
The read() and write() system calls are then used to read from
and write to the accepted socket.
Just a little update for Swift 4.
import Foundation
let sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if sock_fd == -1 {
perror("Failure: creating socket")
exit(EXIT_FAILURE)
}
var sock_opt_on = Int32(1)
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt_on, socklen_t(MemoryLayout.size(ofValue: sock_opt_on)))
var server_addr = sockaddr_in()
let server_addr_size = socklen_t(MemoryLayout.size(ofValue: server_addr))
server_addr.sin_len = UInt8(server_addr_size)
server_addr.sin_family = sa_family_t(AF_INET) // chooses IPv4
server_addr.sin_port = UInt16(12321).bigEndian // chooses the port
let bind_server = withUnsafePointer(to: &server_addr) {
bind(sock_fd, UnsafeRawPointer($0).assumingMemoryBound(to: sockaddr.self), server_addr_size)
}
if bind_server == -1 {
perror("Failure: binding port")
exit(EXIT_FAILURE)
}
if listen(sock_fd, 5) == -1 {
perror("Failure: listening")
exit(EXIT_FAILURE)
}
var client_addr = sockaddr_storage()
var client_addr_len = socklen_t(MemoryLayout.size(ofValue: client_addr))
let client_fd = withUnsafeMutablePointer(to: &client_addr) {
accept(sock_fd, UnsafeMutableRawPointer($0).assumingMemoryBound(to: sockaddr.self), &client_addr_len)
}
if client_fd == -1 {
perror("Failure: accepting connection")
exit(EXIT_FAILURE);
}
To those who came to this topic looking for some help on the same subject, in addition to Martin's answer, I present, below, a small example on how I read and wrote to/from the socket:
// reading one char at a time
var buff_rcvd = CChar()
read(client_fd, &buff_rcvd, 1)
print(NSString(format:"Received: *%c*",buff_rcvd))
// writing one chat at a time
var buff_send: CChar = 65 // character "A" defined as CChar
write(client_fd, &buff_send, 1)
print(NSString(format:"Sent: *%c*",buff_send))
and we must not forget to close the connection after the code is done:
close(sock_fd)
close(client_fd)
EDIT: With FileDescriptors, we can do it even simpler!
let fileHandle = FileHandle(fileDescriptor: client_fd)
let data = fileHandle.readDataToEndOfFile()
print(String(data: data, encoding: .utf8))
Related
I would need to set the AudioQueueBufferRef's mAudioData. I tried with copyMemory:
inBuffer.pointee.copyMemory(from: lastItemOfArray, byteCount: byteCount) // byteCount is 512
but it doesnt't work.
The AudioQueueNewOutput() queue is properly setted up to Int16 pcm format
Here is my code:
class CustomObject {
var pcmInt16DataArray = [UnsafeMutableRawPointer]() // this contains pcmInt16 data
}
let callback: AudioQueueOutputCallback = { (
inUserData: UnsafeMutableRawPointer?,
inAQ: AudioQueueRef,
inBuffer: AudioQueueBufferRef) in
guard let aqp: CustomObject = inUserData?.bindMemory(to: CustomObject.self, capacity: 1).pointee else { return }
var numBytes: UInt32 = inBuffer.pointee.mAudioDataBytesCapacity
/// Set inBuffer.pointee.mAudioData to pcmInt16DataArray.popLast()
/// How can I set the mAudioData here??
inBuffer.pointee.mAudioDataByteSize = numBytes
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil)
}
From apple doc: https://developer.apple.com/documentation/audiotoolbox/audioqueuebuffer?language=objc
mAudioData:
The audio data owned the audio queue buffer. The buffer address cannot be changed.
So I guess the solution would be to set a new value to the same address
Anybody who knows how to do it?
UPDATE:
The incoming audio format is "pcm" signal (Little Endian) sampled at 48kHz. Here are my settings:
var dataFormat = AudioStreamBasicDescription()
dataFormat.mSampleRate = 48000;
dataFormat.mFormatID = kAudioFormatLinearPCM
dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved;
dataFormat.mChannelsPerFrame = 1
dataFormat.mFramesPerPacket = 1
dataFormat.mBitsPerChannel = 16
dataFormat.mBytesPerFrame = 2
dataFormat.mBytesPerPacket = 2
And I am collecting the incoming data to
var pcmData = [UnsafeMutableRawPointer]()
You're close!
Try this:
inBuffer.pointee.mAudioData.copyMemory(from: lastItemOfArray, byteCount: Int(numBytes))
or this:
memcpy(inBuffer.pointee.mAudioData, lastItemOfArray, Int(numBytes))
Audio Queue Services was tough enough to work with when it was pure C. Now that we have to do so much bridging to get the API to work with Swift, it's a real pain. If you have the option, try out AVAudioEngine.
A few other things to check:
Make sure your AudioQueue has the same format that you've defined in your AudioStreamBasicDescription.
var queue: AudioQueueRef?
// assumes userData has already been initialized and configured
AudioQueueNewOutput(&dataFormat, callBack, &userData, nil, nil, 0, &queue)
Confirm you have allocated and primed the queue's buffers.
let numBuffers = 3
// using forced optionals here for brevity
for _ in 0..<numBuffers {
var buffer: AudioQueueBufferRef?
if AudioQueueAllocateBuffer(queue!, userData.bufferByteSize, &buffer) == noErr {
userData.mBuffers.append(buffer!)
callBack(inUserData: &userData, inAQ: queue!, inBuffer: buffer!)
}
}
Consider making your callback a function.
func callBack(inUserData: UnsafeMutableRawPointer?, inAQ: AudioQueueRef, inBuffer: AudioQueueBufferRef) {
let numBytes: UInt32 = inBuffer.pointee.mAudioDataBytesCapacity
memcpy(inBuffer.pointee.mAudioData, pcmData, Int(numBytes))
inBuffer.pointee.mAudioDataByteSize = numBytes
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil)
}
Also, see if you can get some basic PCM data to play through your audio queue before attempting to bring in the server side data.
var pcmData: [Int16] = []
for i in 0..<frameCount {
let element = Int16.random(in: Int16.min...Int16.max) // noise
pcmData.append(Int16(element))
}
I have the following extension on sockaddr:
extension sockaddr {
/// Indicates if this is an IPv4 address.
var isIPv4: Bool {
return sa_family == UInt8(AF_INET)
}
/// Indicates if this is an IPv6 address.
var isIPv6: Bool {
return sa_family == UInt8(AF_INET6)
}
/// Returns the address in string notation.
var address: String? {
var result: String = ""
var me = self
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(&me, socklen_t(me.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
result = String(cString: hostname)
}
return result
}
}
In an other part of my code I'm calling getifaddrs to get the interface addresses of the current device. The code above works fine for IPv4, but is somewhat unreliable for IPv6.
I get results like: 192.168.1.10 and fe80::e0fa:1204:100:0
When I change the line var result: String = "" to var result: String? = nil. The IPv6 addresses suddenly become fe80::, the rest is cut off.
Even weirder, when I just switch the var result and the var me = self lines like this:
extension sockaddr {
/// Indicates if this is an IPv4 address.
var isIPv4: Bool {
return sa_family == UInt8(AF_INET)
}
/// Indicates if this is an IPv6 address.
var isIPv6: Bool {
return sa_family == UInt8(AF_INET6)
}
/// Returns the address in string notation.
var address: String? {
var me = self
var result: String = ""
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(&me, socklen_t(me.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
result = String(cString: hostname)
}
return result
}
}
Then the function will only work for IPv4 addresses. The getnameinfo will return 4 (FAIL).
This is during debugging, with no optimizations that I know of. It doesn't matter if I run it on a simulator or real device.
Could someone please explain why this is happening?
The problem is that getnameinfo expects a pointer that can either be a sockaddr_in or a sockaddr_in6. The definition of the function is a bit confusing because it expects a sockaddr pointer.
Because I'm using an extension to extract the IP address a copy is being made of the memory contents. This isn't a problem for IPv4 because the size of a sockaddr_in is the same size as a sockaddr. However for IPv6, the sockaddr_in6 is larger than the sockaddr struct and some relevant information is cut off.
The order of my commands probably determined what was stored in memory at the location directly after the sockaddr address. Sometimes it would look like a proper IPv6 address, but in reality incorrect.
I've resolved this issue by moving my extension to the network interface ifaddrs:
extension ifaddrs {
/// Returns the IP address.
var ipAddress: String? {
var buffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
let address = ifa_addr.pointee
let result = getnameinfo(ifa_addr, socklen_t(address.sa_len), &buffer, socklen_t(buffer.count), nil, socklen_t(0), NI_NUMERICHOST)
return result == 0 ? String(cString: buffer) : nil
}
}
Thank you #MartinR finding the cause of the problem!
I want to call the Posix socket functions socket and bind from Swift. socket is pretty easy—it takes Int32s, but bind is causing a problem, because I have a sockaddr_in pointer, but it wants a sockaddr pointer. In C, this would be a cast, like:
bind(sock, (struct sockaddr *)&sockAddress, sizeof(sockAddress))
Here's an attempt in Swift:
let sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
var sockAddress = sockaddr_in()
bind(sock, &sockAddress, UInt32(MemoryLayout<sockaddr_in>.size))
The bind line fails to compile with: cannot convert value of type 'sockaddr_in' to expected argument type 'sockaddr'
How do I cast the pointer?
You can write something like this:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
sockaddrInPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) {sockaddrPtr in
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
}
Or someone suggests this may be better:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
let sockaddrPtr = UnsafeRawPointer(sockaddrInPtr).assumingMemoryBound(to: sockaddr.self)
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
This article may be some help.
(UPDATE)
As described in the link shown by Martin R, now MemoryLayout<T>.stride and MemoryLayout<T>.size return the same value which is consistent with C's sizeof, where T is an imported C-struct. I'll keep my stride version of answer here, but that is not something "required" in this case now.
In Swift 3 you have to "rebind" the pointer
(compare SE-0107 UnsafeRawPointer API):
let sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
var sockAddress = sockaddr_in()
let result = withUnsafePointer(to: &sockAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
bind(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.stride))
}
}
Remarks:
The type annotations in let sock: Int32 and var sockAddress: sockaddr_in are not needed.
The memset() is not necessary because sockaddr_in() initializes
all struct members to zero.
The Swift equivalent of the C sizeof is stride (which includes
a possible struct padding), not size (which does not include the
struct padding). (This "problem" does not exist anymore.
For structs imported from C, stride and size have the same value.)
Swift 5 obsolete the withUnsafeBytes(UnsafePointer<sockaddr>), so below is what I'm doing with Swift 5:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
return withUnsafeBytes { (p: UnsafeRawBufferPointer) -> String? in
let addr = p.baseAddress?.assumingMemoryBound(to: sockaddr.self)
guard getnameinfo(addr, socklen_t(self.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
return nil
}
return String(cString: hostname)
}
I saw the question here :
cast-sockaddr-in-to-sockaddr-in-swift 1.2
But when I try to use these code in swift 2.0, I got an error:
var sa = sockaddr_in()
let s = socket(PF_INET,SOCK_STREAM,0)
let cn = connect(s,UnsafeMutablePointer( &sa ), sizeof(sa) )
Ambiguous use of 'init'
How to fix this problem?
Similarly as in the referenced Q&A, you have to use withUnsafePointer()
var sa = sockaddr_in()
let s = socket(PF_INET,SOCK_STREAM,0)
let cn = withUnsafePointer(&sa) {
connect(s, UnsafePointer($0), socklen_t(sizeofValue(sa)))
}
Note also that sizeofValue() must be used with an instance of
a type, and that the value must be converted to socklen_t
as expected by connect().
Update for Swift 3:
let cn = withUnsafeMutablePointer(to: &sa) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
connect(s, $0, socklen_t(MemoryLayout.size(ofValue: sa)))
}
}
I'm trying to do some network code in swift and the type checking is giving me fits.
var sock: CInt = ...
var rin: sockaddr_in
var rlen = socklen_t(sizeof(sockaddr_in))
var buffer: CChar[] = CChar[](count: 128, repeatedValue: 0)
let len = recvfrom(sock, &buffer, 128, 0, &rin, &rlen)
The compiler complains (very cryptically) at the recvfrom about the fact that &rin is a pointer to sockaddr_in instead of sockaddr. I tried various ways to convert the pointer type, but I can't seem to get this right.
If I declare it to be a sockaddr I can get this to compile, but then I can't look at it as a sockaddr_in.
Update for Swift 3 and later, compare UnsafeRawPointer Migration:
var sock: CInt = 1234
var rin = sockaddr_in()
var rlen = socklen_t(MemoryLayout.size(ofValue: rin))
var buffer = [CChar](repeating: 0, count: 128)
let len = withUnsafeMutablePointer(to: &rin) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
recvfrom(sock, &buffer, buffer.count, 0, $0, &rlen)
}
}
Update: As of Swift 1.2 (Xcode 6.3 beta), initializing a C struct
has become much simpler:
var rin = sockaddr_in()
defines a sockaddr_in variable and initializes all elements to zero.
The conversion of a address of sockaddr_in to an an address of
sockaddr is done as follows:
let len = withUnsafeMutablePointer(&rin) {
recvfrom(sock, &buffer, UInt(buffer.count), 0, UnsafeMutablePointer($0), &rlen)
}
Old answer: The first problem is that the sockaddr_in variable has to be initialized before
its address can be passed to recvfrom(). Initializing complex structs in Swift
seems to be clumsy, compare
Swift: Pass Uninitialized C Structure to Imported C function.
Using the helper function from
https://stackoverflow.com/a/24335355/1187415:
func initStruct<S>() -> S {
let struct_pointer = UnsafeMutablePointer<S>.alloc(1)
let struct_memory = struct_pointer.move()
struct_pointer.dealloc(1)
return struct_memory
}
the socket address can be initialized as
var rin : sockaddr_in = initStruct()
To cast the sockaddr_in pointer to a sockaddr pointer, use reinterpretCast().
let len = recvfrom(sock, &buffer, UInt(buffer.count), 0, reinterpretCast(&rin), &rlen)