-1

I am trying to determine whether a TCP port that was bound by a process, that was recently started, is actually in use by that particular process.

Take this program.cpp

int daemonport = 11234;

struct sockaddr_in loopback;
memset ((char*) &loopback, 0, sizeof (loopback));
socklen_t len = sizeof (loopback);
loopback.sin_family = AF_INET;
loopback.sin_port = htons (daemonport);
loopback.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
daemonfd = socket (AF_INET, SOCK_STREAM, 0);
if (daemonfd < 0)
{
    errx (EXIT_FAILURE, "Critical error");
}
if (bind (daemonfd, (struct sockaddr*) &loopback, sizeof (loopback)) != 0)
{
    errx (EXIT_FAILURE, "Daemon already running, TCP port: '%d'", daemonport);
}
if (getsockname (daemonfd, (struct sockaddr*) &loopback, &len) != 0)
{
    errx (EXIT_FAILURE, "Critical error");
}
printf ("%d\n", ntohs (loopback.sin_port));

if (daemon (1, 0) < 0)
{
    close (daemonfd);
    errx (EXIT_FAILURE, "Failed to daemonize!");
}

// event loop...

close (daemonfd);

Now with the tcp socket bound (but not listening) to port 11234 I want to check whether the port is bound by the process using a bash script.

I tried various netstat and lsof patterns w/o success:

netstat -a | grep ':11234' as well as lsof -i :11234.

They all don't print a line with the bound port.

But when I try to run the program a 2nd time it errors out with:

Daemon already running, TCP port: '11234'
Ben
  • 807
  • 1
  • 8
  • 22

2 Answers2

2

Assuming Linux, start with this:

netstat --inet -n -a -p | grep ':myport'

and see what you're getting. The --inet keeps from showing IP6 and Unix domain sockets. -n shows numerical results and not names translated from the port number. -p tells you which process is listening on it.

If any of those lines lay "LISTEN" then a process is lisening on that port. However, any open connections using that port (even "TIME_WAIT") will prevent the port from being re-opened unless you use the SO_REUSEPORT option every time you bind to it.

If that command isn't showing you anything then nothing is listening on that port which means there must be a problem with your program.

You're printing an error message but assuming the problem is something already running. Print out the errno value (use perror(...)) so you can exactly what the problem is.

Community
  • 1
  • 1
Brian White
  • 8,332
  • 2
  • 43
  • 67
  • If I add `perror(...)` for the bind error check it prints `Address already in use` as expected. That is when I try to run the program while another instance of it is already bound to the port. `netstat --inet -n -a -p | grep ':11234'` doesn't show anything apart from the usual info for not being root. – Ben Apr 02 '15 at 11:52
  • If something is using the port, `netstat` will show it. If you've recently run your program, used it, exited, and now it won't run again, it's an SO_REUSE problem. – Brian White Apr 02 '15 at 11:56
  • The point is that the program is still running and therefore the socket ain't closed and a 2nd instance fails to bind to the same port which is exactly what I want to achieve. However, `netstat` does not show me the program associated with that port. `SO_REUSEPORT` does not seem to be available on my debian os. If I set `SO_REUSEADDR` instead the 2nd instance won't error out at bind which makes sense but it not what I want. – Ben Apr 02 '15 at 12:15
  • As a matter of fact: As soon as I terminate the first instance the socket gets closed and once I run the program again it doesn't error out. The thing I am saying is that the port binding does seem to work as it should. – Ben Apr 02 '15 at 12:17
  • All sockets will get closed when your program exits but that doesn't mean they cease to exist. TCP will go through its shut-down phase which often includes a couple minutes of "TIME_WAIT" for previously established connections during which the port number is still "in use" (unless you use SO_REUSEPORT) when trying to bind to it again. – Brian White Apr 02 '15 at 12:32
0

By way of example, to check to see if port 56789 is available locally:

port=56789
retval=$(python3 -c 'import socket; s=socket.socket(); s.bind(("", '"${port}"')); print(s.getsockname()[1]); s.close()' 2>/dev/null)
echo "$retval"

This will print a blank line if the port is already bound, and will print 56789 if it is not bound. If port 56789 was recently used and closed, but the TIME_WAIT period has not yet elapsed (typically one or two minutes), then the port will not be available and the above code will not echo 56789.

I realize that this is a bit of a cheat, because it also uses python, but it is bash scriptable if python 3 is available. No sudo required.

Generic Ratzlaugh
  • 717
  • 1
  • 6
  • 13