Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ check TCP port

Tags:

c++

I have written a program in C++ and i need to check if a TCP port is truely empty.

This is the function :

int checkport(char* host, char* port, int timeout)
{
    int sock;
    struct sockaddr_in sin;
    int result = 0;

    sock = socket(AF_INET, SOCK_STREAM, 0);

    sin.sin_family = AF_INET;
    sin.sin_port = htons(atoi(port));
    sin.sin_addr.s_addr = inet_addr(host);
    fd_set fdset;
    struct timeval tv;
    fcntl(sock, F_SETFL, O_NONBLOCK);

    int connect_result = connect(sock,(struct sockaddr*)(&sin),sizeof(struct sockaddr_in));
    FD_ZERO(&fdset);
    FD_SET(sock, &fdset);
    tv.tv_sec = timeout;
    tv.tv_usec = 0;

    int select_result = select(sock + 1, NULL, &fdset, NULL, &tv);

    // printf("connect = [%d] | select = [%d]\n",connect_result,select_result);

    if(select_result == 1)
    {
        int so_error;
        socklen_t len = sizeof so_error;
        getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);

        // printf("so_error = [%d] \n",so_error);

        if(so_error == 0)
        {
            //Is connected
            if(hitdebug >= 4) puts("CONNECTED");
            if(hitdebug >= 2) printf("[%s:%s] OPEN\n",host,port);

            result = 1;
        }
        else
        {
            if(hitdebug >= 4) puts("CONNECT_ERROR_1");

            result = 0;

        }
    }
    else
    {
        if(hitdebug >= 4) puts("CONNECT_ERROR_2");

        result = 0;
    }

    close(sock);

    return result;
}

The problem is that is detecting only LISTEN port, i want a port to be 100% true and even detect ESTABLISHED, TIME_WAIT, etc ...

Output :

connect = [-1] | select = [1]
so_error = [111]
50983 TEST=[0]
tcp        0      0 1.2.3.4:50983       4.4.4.4:22       ESTABLISHED


connect = [-1] | select = [1]
so_error = [111]
43343 TEST=[0]
tcp        0      0 1.2.3.4:43343       4.4.4.4:22       ESTABLISHED


connect = [-1] | select = [1]
so_error = [0]
64000 TEST=[1]
tcp        0      0 1.2.3.4:64000       0.0.0.0:*               LISTEN
tcp        0      0 1.2.3.4:47669       1.2.3.4:64000       TIME_WAIT


connect = [-1] | select = [1]
so_error = [111]
54674 TEST=[0]


connect = [-1] | select = [1]
so_error = [111]
54665 TEST=[0]

For me an empty port is when i do a netstat -an | grep 12345 | wc -l and i see 0, not even a FIN_WAIT

How can i accomplish that?

Thank you.

like image 581
Damian Avatar asked Jun 23 '17 13:06

Damian


2 Answers

if (the_port_is_free(port_number)) {
   /* is the port free at this point? */
}

The correct answer is "who knows?" Sure, it was free a nanosecond ago when the control was somewhere in the function the_port_is_free, but is it free now? There are many other processes around, perhaps one of them took the port half a nanosecond ago?

This is called a race condition. Every programmer should understand the concept.

It is precisely because of this problem the_port_is_free is not provided by your OS: it only would give you false expectations, not correct answers. You cannot know whether the port is free now and, more importantly, will be free in a nanosecond when you decide to bind it. The only way to bind the port is to go ahead and try binding it.

This approach applies to a whole bunch of situations. Whenever there's a shared resource of any kind, there's usually no function that tells you if it's OK to grab it. The only way to get it is to go ahead and try.

like image 52
n. 1.8e9-where's-my-share m. Avatar answered Oct 17 '22 04:10

n. 1.8e9-where's-my-share m.


Just try to bind the port for listening - if it fails (with SO_REUSEADDR off, which is the default), then the socket is either in active use or in one of the WAIT states.

like image 8
Useless Avatar answered Oct 17 '22 03:10

Useless