Search code examples
swiftsocketstcpdarwinswift3

Swift TCP: safe buffer size for `Darwin.send` function


I'm building a small and easy to use TCP framework in Swift 3 for macOS and iOS (someday it will support Linux). This is something new that I explore and thats why there is potential of confusion and bugs.

My internal code looks like this:

if Darwin.send(self._fileDescriptor._value, data.withUnsafeBytes { $0 }, data.count, 0)._isMinusOne() {

    try Error._throw(type: .network)
}

Sending small packages is not a problem, but when I tried to send a large package my application crashed (I was trying to send 1590784 bytes at once). After that I investigated the problem and found out that I missed the limit I can pass to Darwin.send function. I've been searching on the web to find a good answer, but unfortunately there are a few numbers I found about this specific topic (65K, 1500, etc.).

My question is what maximum buffer size should I use in Darwin.send function to always be on the safe side?

I'm not that experienced in that particular area, so it would be nice if the answer to my question would explain why do you think the size you have chosen is the best and safest choice.


Solution

  • I didn't know there was a limit to the size of the buffer you can pass to send().

    However, it is not safe to return the pointer you get as a parameter to your block in data.withUnsafeBytes. I don't think you can guarantee it points to a valid memory region after the block returns.

    You should try

    let bytesSent = data.withUnsafeBytes{
        return Darwin.send(self._fileDescriptor._value, $0, data.count, 0)
    }
    

    Update

    I have checked the source code for withUnsafeBytes and I can confirm that no effort is made by the method call to preserve the memory pointed to beyond the scope of the closure you pass to it. What you are trying to do is reference memory after it has been deallocated. I'm sure this is the source of your crash.