swrap: Add support for bindresvport().
authorAndreas Schneider <asn@samba.org>
Tue, 20 May 2014 18:04:02 +0000 (20:04 +0200)
committerMichael Adam <obnox@samba.org>
Sat, 31 May 2014 10:32:09 +0000 (12:32 +0200)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
ConfigureChecks.cmake
config.h.cmake
src/socket_wrapper.c

index 3a31f50b2b314cb315d86c1e694cd9c857638522..44914f02c67b73d97af2a41cb19fb781c3f3b998 100644 (file)
@@ -60,6 +60,10 @@ check_function_exists(snprintf HAVE_SNPRINTF)
 check_function_exists(signalfd HAVE_SIGNALFD)
 check_function_exists(eventfd HAVE_EVENTFD)
 check_function_exists(timerfd_create HAVE_TIMERFD_CREATE)
+set(CMAKE_REQUIRED_FLAGS -D_GNU_SOURCE)
+check_function_exists(bindresvport HAVE_BINDRESVPORT)
+set(CMAKE_REQUIRED_FLAGS)
+
 
 if (UNIX)
     if (NOT LINUX)
index 02c016ef150d548768d14c840ae3690436cc94eb..b5dd8c9bc55cb009f79f02b89746b96f7a096553 100644 (file)
@@ -37,6 +37,7 @@
 #cmakedefine HAVE_SIGNALFD 1
 #cmakedefine HAVE_EVENTFD 1
 #cmakedefine HAVE_TIMERFD_CREATE 1
+#cmakedefine HAVE_BINDRESVPORT 1
 
 #cmakedefine HAVE_ACCEPT_PSOCKLEN_T 1
 #cmakedefine HAVE_IOCTL_INT 1
index 5bedfa79c2fba504da09d4497dc001c32975f3dd..bf84dbe516954f3ec94a33164a73d032c1c6377a 100644 (file)
@@ -111,6 +111,13 @@ enum swrap_dbglvl_e {
 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
 #endif
 
+#ifndef ZERO_STRUCTP
+#define ZERO_STRUCTP(x) do { \
+               if ((x) != NULL) \
+                       memset((char *)(x), 0, sizeof(*(x))); \
+       } while(0)
+#endif
+
 #ifndef discard_const
 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
 #endif
@@ -2752,6 +2759,86 @@ int bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
        return swrap_bind(s, myaddr, addrlen);
 }
 
+/****************************************************************************
+ *   BINDRESVPORT
+ ***************************************************************************/
+
+#ifdef HAVE_BINDRESVPORT
+static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen);
+
+static int swrap_bindresvport_sa(int sd, struct sockaddr *sa)
+{
+       struct sockaddr_storage myaddr;
+       socklen_t salen;
+       static uint16_t port;
+       uint16_t i;
+       int rc = -1;
+       int af;
+
+#define SWRAP_STARTPORT 600
+#define SWRAP_ENDPORT (IPPORT_RESERVED - 1)
+#define SWRAP_NPORTS (SWRAP_ENDPORT - SWRAP_STARTPORT + 1)
+
+       if (port == 0) {
+               port = (getpid() % SWRAP_NPORTS) + SWRAP_STARTPORT;
+       }
+
+       if (sa == NULL) {
+               salen = sizeof(struct sockaddr);
+               sa = (struct sockaddr *)&myaddr;
+
+               rc = swrap_getsockname(sd, (struct sockaddr *)&myaddr, &salen);
+               if (rc < 0) {
+                       return -1;
+               }
+
+               af = sa->sa_family;
+               memset(&myaddr, 0, salen);
+       } else {
+               af = sa->sa_family;
+       }
+
+       for (i = 0; i < SWRAP_NPORTS; i++, port++) {
+               switch(af) {
+               case AF_INET: {
+                       struct sockaddr_in *sinp = (struct sockaddr_in *)sa;
+
+                       salen = sizeof(struct sockaddr_in);
+                       sinp->sin_port = htons(port);
+                       break;
+               }
+               case AF_INET6: {
+                       struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)sa;
+
+                       salen = sizeof(struct sockaddr_in6);
+                       sin6p->sin6_port = htons(port);
+                       break;
+               }
+               default:
+                       errno = EAFNOSUPPORT;
+                       return -1;
+               }
+               sa->sa_family = af;
+
+               if (port > SWRAP_ENDPORT) {
+                       port = SWRAP_STARTPORT;
+               }
+
+               rc = swrap_bind(sd, (struct sockaddr *)sa, salen);
+               if (rc == 0 || errno != EADDRINUSE) {
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+int bindresvport(int sockfd, struct sockaddr_in *sinp)
+{
+       return swrap_bindresvport_sa(sockfd, (struct sockaddr *)sinp);
+}
+#endif
+
 /****************************************************************************
  *   LISTEN
  ***************************************************************************/