0

I'm writing a C program for client-server communication infrastructure.

My basic target is allowing a connection trial to last 15 seconds at least before it timesout. Meaning, while connecting to a server, I want the client to wait for 15 seconds at most for the server to response and accept this connection trial. After 15 seconds without a successful connection I want to return a timeout indication.

So far I was able to make the socket non-blocking using ioctlsocket() and then using select() to wait for 15 seconds. I have been using Remy Lebeau's function:

Winsock C++ connect timeout

But, my problem is when trying to connect from the client to the server, when the server is not opened yet, in this 15 seconds period. I try to open the server while the client is attempting to connect to it and not before (within the 15 sec period), but it seems that "exceptfds" set is being "signaled" first and distrupts the time alloted for the timeout.

If I don't use the "exceptfds", and use only "writefds" I'm able to wait for 15 seconds timeout, but can't connect to the server in the 15 seconds period - so I'm only experiencing the timeout period and can't use it to connect.

I've read somewhere that select() return even if the timeout has yet been reached, if one of the sets is "signaled" - is there a way to overcome this? I don't want to use any time libraries as well.

Here is my code:

non_blocking_ret_val connect_non_blocking(SOCKET sock, const char *ip_addr, u_short port_num){

int ret = 0;

SOCKADDR_IN server = { 0 };
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(ip_addr);
server.sin_port = htons(port_num);

// ipaddr valid?
if (server.sin_addr.s_addr == INADDR_NONE) {
    printf_s("Error in converting ip address. Terminating...\n");
    return CONNECTION_ERROR;
}

// put socket in non-blocking mode...
if (SOCKET_ERROR == set_blocking(sock, FALSE))
    return SOCKET_ERROR;

if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
    if (WSAGetLastError() != WSAEWOULDBLOCK)
    {
        // connection failed
        //close_socket_and_deinit_wsa(sock);
        printf_s("Making the connect function a non-blocking one failed, %ld. Terminating...\n", WSAGetLastError());
        return CONNECTION_ERROR;
    }

    // connection pending

    fd_set setW, setE;

    FD_ZERO(&setW);
    FD_SET(sock, &setW);
    FD_ZERO(&setE);
    FD_SET(sock, &setE);

    TIMEVAL time_out = { 0 };
    time_out.tv_sec = CLIENT_CONNECT_TIMEOUT;
    time_out.tv_usec = 0;

    ret = select(0, NULL, &setW, &setE, &time_out);
    if (ret <= 0)
    {
        // select() failed or connection timed out
        if (ret == 0) {
            WSASetLastError(WSAETIMEDOUT);
            return CONNECTION_TIMEOUT;
        }
        //close_socket(sock);
        printf_s("select() function has unexpectedly failed. Terminating...\n");
        return CONNECTION_ERROR;
    }

    if (FD_ISSET(sock, &setE))
    {
        // connection failed
        int err = 0;
        getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, sizeof(err));
        WSASetLastError(err);
        printf_s("Connection to server has failed. Terminating...\n");
        return CONNECTION_FAILED;
    }
}

// connection successful

// put socket in blocking mode...
if (SOCKET_ERROR == set_blocking(sock, TRUE))
    return CONNECTION_ERROR;

return CONNECTION_SUCCEEDED;

}

int set_blocking(SOCKET m_socket, BOOL is_blocking){
unsigned long non_blocking = 1;
unsigned long blocking = 0;
int result = ioctlsocket(m_socket, FIONBIO, is_blocking ? &blocking : &non_blocking);
if (result == SOCKET_ERROR)
    printf_s("Error no.%ld in using ioctlsocket(). Terminating...\n", WSAGetLastError());
return result;

}

Thanks!

  • Is it possible that the connection takes less than 15 seconds to fail? For example, if the server computer replies with a "connection refused" packet? – user253751 Jan 15 '21 at 17:34
  • Yes. It’s possible. But I can apply this only if the connection was successful, right? Otherwise, it’s a matter of sending messages on a failed connection – Aviram Dick Jan 15 '21 at 18:14
  • You can't send messages on a failed connection. What do you think failed means? – user253751 Jan 15 '21 at 19:41

0 Answers0