/*
 * free_tcp_port
 *
 * Try to find a probably(!!) free port which can be forwarded by SSH.
 *
 * Idea: Open a TCP socket and let UNIX find a free port, close the socket 
 *       and print the port number.
 *       Normally UNIX assignes port numbers one after the other. 
 *       Therefore the next application should not get the same port as we.
 *       This is not absolutely safe but should work in practice.
 *
 * 26 Jan 1996, hot@informatik.tu-chemnitz.de
 *
 * compilation:

    gcc -O2 -o free_tcp_port -s free_tcp_port.c

 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>

/*
 * MAIN
 */
int
main(int argc, char **argv)
{
  struct sockaddr_in tcp_addr; /* TCP address to be forwarded by SSH */

  struct hostent *hp;          /* for gethostbyname */

  int addr_len,                /* length of a socket address */
      tcp_sockfd;              /* TCP socket descriptor */

  /*
   * resolve "localhost"
   */
  if ((hp = gethostbyname("localhost")) == NULL)
  {
    fprintf(stderr, "can't resolve localhost\n");
    exit(1);
  }

  /* 
   * create a TCP listening socket
   */

  if ((tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  {
    perror("can't open stream socket for server");
    exit(1);
  }

  bzero((char *) &tcp_addr, sizeof(tcp_addr));
  tcp_addr.sin_family      = AF_INET;
  bcopy((char *)hp->h_addr,(char *)&tcp_addr.sin_addr, hp->h_length);
  tcp_addr.sin_port        = htons(0);

  /*
   * bind the socket
   */

  if (bind(tcp_sockfd, (struct sockaddr *) &tcp_addr, sizeof(tcp_addr)) < 0)
  {
    fprintf(stderr, "can't bind local address for server\n");
    exit(1);
  }

  /* 
   * read the binding back 
   */

  addr_len = sizeof(tcp_addr);
  getsockname(tcp_sockfd, (struct sockaddr *) &tcp_addr, &addr_len);

  /*
   * print the free port number
   */

  printf("%d\n", ntohs(tcp_addr.sin_port));

  /*
   * close the socket (and hope nobody will "steal" it till SSH grabs it)
   */

  close(tcp_sockfd);
}
