5

This question is very similar (or almost identical) to In a non blocking socket connect, select() always returns 1; however, I can't seem to find where my code is faltering.

I am using non-blocking sockets and want to use select() when connecting a client to a server to check for timeout/success. The problem is select() is always returning 1 almost immediately, even when I don't even have the server running and there is nothing to connect to. Thanks in advance for the help, code snippet is as follows:

//Loop through the addrinfo structs and try to connect to the first one we can
for(p = serverinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
    {
        //We couldn't create the socket, try again
        perror("client: socket");
        continue;
    }

    //Set the socket to non-blocking
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        //The error was something other than non-block/in progress, try next addrinfo
        if(errno != EINPROGRESS) 
        {
            close(sockfd);
            perror("client: connect");
            continue;
        }

        fd_set write_fds;
        FD_ZERO(&write_fds);            //Zero out the file descriptor set
        FD_SET(sockfd, &write_fds);     //Set the current socket file descriptor into the set

        //We are going to use select to wait for the socket to connect
        struct timeval tv;              //Time value struct declaration
        tv.tv_sec = 5;                  //The second portion of the struct
        tv.tv_usec = 0;                 //The microsecond portion of the struct

        //DEBUG: This is ALWAYS 1
        int select_ret = select(sockfd + 1, NULL, &write_fds, NULL, &tv);
        cout << select_ret << endl;

        //Check return, -1 is error, 0 is timeout
        if(select_ret == -1 || select_ret == 0)
        {
            //We had an error connecting
            cout << "Error Connecting\n";
            close(sockfd);
            continue;
        }
    }

    //We successfully connected, break out of loop
    break;
}
Community
  • 1
  • 1
Darren Swanson
  • 53
  • 1
  • 1
  • 3
  • Thos is almost a duplicate of http://stackoverflow.com/questions/8417821/non-blocking-socket-select-returns-1-after-connect?rq=1 – Zan Lynx Jan 30 '14 at 01:45

2 Answers2

4

What do you expect select() to return? Consider that select() is normally used to wait for multiple file descriptors - if you were connecting two, how would you know which one succeeded/failed based purely on the return value of select? You wouldn't, obviously.

Which is why select() just tells you which file descriptors have changed in some way, and you're supposed to determine independently what that was. In the case of connect(), you should call getsockopt() to retrieve the result of the connection attempt. See this answer where I explain how to do a non-blocking connect().

Community
  • 1
  • 1
Ambroz Bizjak
  • 7,809
  • 1
  • 38
  • 49
  • 1
    That's not what it says in the documentation. You're supposed to call connect() again. – user207421 Jul 01 '12 at 22:38
  • EJP I saw in the documentation that explains how to do it the way Ambroz describes, is that the better approach? – Darren Swanson Jul 01 '12 at 22:49
  • 5
    @EJP I'm interested to know what documentation you're talking about. The official method in the Linux connect(2) man page is to getsockopt(fd, SOL_SOCKET, SO_ERROR, ...) which I know because I wrote that part of the man page. Long ago I wrote a program using the "connect-again" method. It worked for me, but not for BSD users, who insisted that the second connect was a stupid Linux-only thing. – Alan Curry Jul 01 '12 at 23:18
  • Our production SW uses getsockopt with (SOL_SOCKET, SO_ERROR) when the socket turns to writable. And it works well. Maybe EJP have another working way. But this answer is correct. – SKi Jul 04 '12 at 10:57
  • select() returns the number of active sockets on return. It doesn't always return 1. This doesn't answer the question. – Glenn Maynard Nov 25 '13 at 16:05
  • @EJP: That's the info I was looking for. Don't want to hijack this post, but created a similar one here: http://stackoverflow.com/questions/35801679/cant-seem-to-get-a-timeout-working-when-connecting-to-a-socket. Then it dawned on me that I probably need to call connect() again when the socket is writable. Just like if I'm doing a non-blocking read(), if I get E_AGAIN, I need to call read() again when I detect there are bytes available as the OS isn't going to do the read() for me. –  Apr 04 '16 at 21:10
1

When connecting in non-blocking mode and select() indicates the connection is writeable, you are then supposed to call connect() again. Doing so will return -1 with errno == ECONNRESET or whatever it is.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 3
    Really? Can you reference something which guarantees this will work, as opposed to starting a new connection attempt? The linux man page for connect states (explaining the EINPROGRESS error): After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to detemine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure). – Ambroz Bizjak Jul 01 '12 at 22:37
  • @AmbrozBizjak Stevens and Wright, *TCP/IP Illustrated;* Stevens, Unix Network Programming;* and Douglas Comer's TCP book whose name misremember. – user207421 Jul 04 '14 at 15:01
  • Sorry, probably should have commented on this answer rather than the one above. I'm running into a similar issue and figured that I probably need to call connect() again, but all the searching, other than this post, didn't indicate such. Also, the docs for connect don't mention that. In fact ECONNRESET is not even listed as a possible error of connect(). I however do see EISCONN. –  Apr 04 '16 at 21:23