SO_ERROR vs. errno

15,199

Solution 1

Quoting Dan Bernstein:

Situation: You set up a non-blocking socket and do a connect() that returns -1/EINPROGRESS or -1/EWOULDBLOCK. You select() the socket for writability. This returns as soon as the connection succeeds or fails. (Exception: Under some old versions of Ultrix, select() wouldn't notice failure before the 75-second timeout.)

Question: What do you do after select() returns writability? Did the connection fail? If so, how did it fail?

If the connection failed, the reason is hidden away inside something called so_error in the socket. Modern systems let you see so_error with getsockopt(,,SO_ERROR,,) ...

He goes on to discuss the fact that getsockopt(,,SO_ERROR,,) is a modern invention that doesn't work on old systems, and how to get the error code on such systems. But you probably don't need to worry about that if you're programming for a Unix/Linux system released in the last 15 years.

The Linux man page for connect describes the same usage of SO_ERROR.

So, if you're performing asynchronous operations on sockets, you may need to use SO_ERROR. In any other case, just use errno.

Solution 2

Quoting Unix Network Programming:

If so_error is nonzero when the process calls read and there is no data to return, read returns–1 with errno set to the value of so_error (p. 516 of TCPv2). The value of so_error is then reset to 0. If there is data queued for the socket, that data is returned by read instead of the error condition. If so_error is nonzero when the process calls write, –1 is returned with errno set to the value of so_error (p. 495 of TCPv2) and so_error is reset to 0.

So, errno is the better choice, unless you want to get error immediately before the data is fully fetched.

Share:
15,199
Félix Faisant
Author by

Félix Faisant

Updated on July 20, 2022

Comments

  • Félix Faisant
    Félix Faisant almost 2 years

    For getting socket syscall (like recv) error, which is better (at performance level) ?

    • Use the plain old errno
    • Or use SO_ERROR as getsockopt() optname ?

    I think errno (defined to __error() on my system) is faster because it's not a system call. Am I right ?

    The advantages of SO_ERROR are : automatic error reset after getting, and we are sure that the error only concerns our socket. It's safer.

    Which one do you think is better ? Is there a really difference of performance between the two ?

  • user207421
    user207421 over 10 years
    Dan Bernstein is incorrect about 'old versions of Ultrix'. The 75-second timeout is still there. select() notices a connection failure earlier if there was an active refusal by the peer, i.e. a response. If there was no response at all, the timeout still applies. The precise timeout period is platform-dependent.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE over 10 years
    @EJP: There is no failure until the timeout passes with no response.
  • rob mayoff
    rob mayoff over 9 years
    @EJP I believe djb's point is that some old versions of Ultrix wouldn't report an active refusal (e.g. a RST packet) until the 75 second timeout expired, regardless of when the refusal happened. That is independent of whether Ultrix or any other system reports failure after 75 seconds of no response.
  • JustAMartin
    JustAMartin over 7 years
    And what about exceptfds? Microsoft says: msdn.microsoft.com/en-us/library/windows/desktop/… "If a socket is processing a connect call (nonblocking), failure of the connect attempt is indicated in exceptfds (application must then call getsockopt SO_ERROR to determine the error value)." - is this exceptfds behavior Win-specific or does it work on *nixes also?
  • rob mayoff
    rob mayoff over 7 years
    Historically, the only use of exceptfds was to detect TCP out-of-band data. Whether some systems now use it for other things, I can't say.
  • Remy Lebeau
    Remy Lebeau over 2 years
    AFAIK, Windows is the only system that uses exceptfds to report a non-blocking connect() failure.