Updated for AES encryption.
[m6w6/libmemcached] / libtest / port.cc
index 9bd7717f469675c031c2a58c086cf7d65b73b9ee..fefb6a6d394ada0c72b0c480b61b7b38c140a406 100644 (file)
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <config.h>
 #include <libtest/common.h>
 
 #include <cassert>
 #include <cstdlib>
 #include <cstring>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <unistd.h>
 #include <ctime>
 #include <fnmatch.h>
 #include <iostream>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h> 
+#include <sys/wait.h>
+#include <unistd.h>
 
 #include <signal.h>
 
 
 using namespace libtest;
 
+struct socket_st {
+  std::vector<int> fd;
+
+  ~socket_st()
+  {
+    for(std::vector<int>::iterator iter= fd.begin(); iter != fd.end(); iter++)
+    {
+      close(*iter);
+    }
+  }
+};
+
+static socket_st all_socket_fd;
+
 static in_port_t global_port= 0;
-static in_port_t global_max_port= 0;
+
+namespace libtest {
 
 in_port_t default_port()
 {
+  if (global_port == 0)
+  {
+    global_port= get_free_port();
+  }
+
   return global_port;
 }
-void set_default_port(in_port_t port)
-{
-  global_port= port;
-}
 
-in_port_t max_port()
-{
-  return global_max_port;
-}
-void set_max_port(in_port_t port)
+in_port_t get_free_port()
 {
-  if (port > global_max_port)
+  in_port_t ret_port= in_port_t(0);
+
+  int retries= 1024;
+
+  while (retries--)
   {
-    global_max_port= port;
+    int sd;
+    if ((sd= socket(AF_INET, SOCK_STREAM, 0)) != -1)
+    {
+      int optval= 1;
+      if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != -1)
+      {
+        struct sockaddr_in sin;
+        sin.sin_port= 0;
+        sin.sin_addr.s_addr= 0;
+        sin.sin_addr.s_addr= INADDR_ANY;
+        sin.sin_family= AF_INET;
+
+        if (bind(sd, (struct sockaddr *)&sin,sizeof(struct sockaddr_in) ) != -1)
+        {
+          socklen_t addrlen= sizeof(sin);
+
+          if (getsockname(sd, (struct sockaddr *)&sin, &addrlen) != -1)
+          {
+            ret_port= sin.sin_port;
+          }
+        }
+      }
+
+      all_socket_fd.fd.push_back(sd);
+    }
+
+    if (ret_port > 1024)
+    {
+      break;
+    }
   }
 
-  global_max_port= port;
+  // We handle the case where if we max out retries, we still abort.
+  if (ret_port <= 1024)
+  {
+    fatal_message("No port could be found");
+  }
+
+  return ret_port;
 }
+
+} // namespace libtest