-1

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.

DevAndArtist
  • 4,971
  • 1
  • 23
  • 48
  • XY problem. Define 'crashed'. Provide symptoms. Evidence. Problem. Leave the guesswork at home. – user207421 Jun 18 '16 at 10:10
  • @EJP The question was crystal clear! JeremyP gave me great feedback to solve my problem. I didn't asked for why my application crashed in first place! – DevAndArtist Jun 18 '16 at 10:45

1 Answers1

2

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.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • As far as I now can say the limitation is physical and not logical. As I mentioned in my post my application crashes when I pass a very large buffer to the function. I modified my code to send inside the closure (good catch) but the result is the same. Right now I'm rebuilding the my custom send algorithm to split the data into smaller packages and see if the mentioned issue will go away (I think it should), but my question remains the same: what buffer size is safe for `Darwin.send`!? – DevAndArtist Jun 17 '16 at 15:21
  • Okay I can now confirm that this approach by slicing data into smaller packages works great and as expected (at least on my MacBook). – DevAndArtist Jun 17 '16 at 16:01
  • @DevAndArtist There is no limit to the buffer you pass to the send system call. What happens is it sends what it can and returns the number of bytes sent (or -1 if there is an error). The size of the buffer is not the problem. – JeremyP Jun 18 '16 at 09:50
  • So that might mean that I have to check if the result of `send` is not equal to the my data I was sending and resend the rest (on each iteration I'll check for -1). Is that correct? I'd now assume, that this way it wouldn't matter if my data is bigger than the socket buffer size. – DevAndArtist Jun 18 '16 at 09:57
  • @DevAndArtist That is correct. I think I would do it by putting my fragment in a loop and then replacing the data by a subdata (using the `subData()` method) until my data was of zero size(or an error occurred). – JeremyP Jun 18 '16 at 10:01
  • I'm assuming this is TCP. If it is UDP there absolutely is a limit to the size you can pass in one `send` call. – JeremyP Jun 18 '16 at 10:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/114999/discussion-between-devandartist-and-jeremyp). – DevAndArtist Jun 18 '16 at 10:32
  • I accepted your answer and your feedback as the right answer. – DevAndArtist Jun 18 '16 at 10:46