Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

connect() returns "Operation now in progress" on blocking socket?

I have a blocking socket (at least it appears so in following code):

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0) {
            ERROR("%s: error opening socket", __func__);
            return (RESP_ERROR);
    }

    t.tv_sec = timeout;
    t.tv_usec = 0;

    int rf = fcntl(sock, F_GETFD);
    ERROR("fcntl ret=%d, ret & O_NONBLOCK = %d", rf, rf & O_NONBLOCK);

    if ((setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&t, sizeof (t)) < 0)
        || (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&t, sizeof (t)))) {
            strerror_r(errno, err, 254);
            ERROR("%s: error on setsockopt -> %s", __func__, err);
            close(sock);
            return (RESP_ERROR);
    }

    rf = fcntl(sock, F_GETFD);
    ERROR("after select fcntl ret=%d, ret & O_NONBLOCK = %d", rf, rf & O_NONBLOCK);

    if (connect(sock, (struct sockaddr *)&dst, sizeof (dst)) != 0) {
            strerror_r(errno, err, 254);
            ERROR("%s: error on connect -> %s", __func__, err);
            close(sock);
            return (RESP_ERROR);
    }

And this is from log:

Mar 6 10:42:04 tcpclient: fcntl ret=0, ret & O_NONBLOCK = 0

Mar 6 10:42:04 tcpclient: after select fcntl ret=0, ret & O_NONBLOCK = 0

Mar 6 10:42:14 tcpclient: authenticate: error on connect -> Operation now in progress

It appears this is a blocking socket but returns error typical for non-blocking? Linux is 2.6.18-308.el5. Any ideas?

like image 597
Ivan Ostres Avatar asked Mar 06 '13 09:03

Ivan Ostres


1 Answers

If timeout is not 0 the call to connect() times out and returns. This happens independently of whether a connection was established or not.

From the moment the time-out expired connect() behaves as if called on a non-blocking socket.

Referring this case (verbatim from man connect and ignore "immediately" below):

EINPROGRESS

The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explain‐ ing the reason for the failure).


Btw: Could someone confirm this is standard behaviour, and for this explicitly mentioned somewhere?

man 7 socket states (italics by me):

SO_RCVTIMEO and SO_SNDTIMEO

Specify the receiving or sending timeouts until reporting an error. [...] if no data has been transferred and the timeout has been reached then -1 is returned with errno set to EAGAIN or EWOULDBLOCK just as if the socket was specified to be nonblocking. [...] Timeouts only have effect for system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), etc.

No word regarding connect()so I'm unsure my answer does hold.

like image 69
alk Avatar answered Sep 23 '22 11:09

alk