2 Replies
      Latest reply on Aug 20, 2015 2:19 AM by eskimo
      jphughes Level 1 Level 1 (0 points)

        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.

          • Re: Swift setsockopt SOL_SOCKET SO_RCVTIMEO gets invalid argument
            eskimo Apple Staff Apple Staff (10,925 points)

            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"