Swift setsockopt SOL_SOCKET SO_RCVTIMEO gets invalid argument

The following playground demonstrates the problem.


import Foundation 
var s = socket(AF_INET, SOCK_STREAM, 0) 
var tv = timeval() 
tv.tv_sec = 3 
tv.tv_usec = 100000 
let tvSize = socklen_t(sizeof(timeval)) 
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, tvSize) 
NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)


The result is setsockopt gets -1 and NSError returns


Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument"


This is Mac OS X 10.11, xcode Version 7.0 beta 5 (7A176x). Any help will be greatly appreciated.

See the answer you got to your exact same post on Stack Overflow.

Alas, that answer is incorrect. If it were, then the following C code would also fail, which it does not.

BOOL            success;
int            s;
struct timeval  tv = {3, 100000};

s = socket(AF_INET, SOCK_STREAM, 0);
success = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == 0;
if (success) {
    NSLog(@"success");
} else {
    NSLog(@"error %d", errno);
}

The actual issue relates to

sizeof
. In C this returns 16 (at least in the 64-bit case, which is what I was testing), whereas in Swift it returns 12. That’s a well-known discrepancy related to how padding at the end of structures is handled. If you want the C value from Swift, use
strideof
. So, with the following single line change, jphughes’s Swift code works just fine.
let tvSize = socklen_t(strideof(timeval))

Except that you’re not allowed to look at

errno
without confirming that you did actually get an error by first checking the function result. So the end of the code should look more like the C code I posted above:
let success = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, tvSize) == 0
if success {
    NSLog("success");
} else {
    NSLog("error %d", errno);
}

ps I filed a bug to get the

strideof
gotcha discussed in the "Interacting with C APIs" section of "Using Swift with Cocoa and Objective-C" (r. 22358549)

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Swift setsockopt SOL_SOCKET SO_RCVTIMEO gets invalid argument
 
 
Q