swrap: Add support for bindresvport().
authorAndreas Schneider <asn@samba.org>
Tue, 3 Jun 2014 13:10:19 +0000 (15:10 +0200)
committerMichael Adam <obnox@samba.org>
Thu, 5 Jun 2014 21:57:10 +0000 (23:57 +0200)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
lib/socket_wrapper/socket_wrapper.c
lib/socket_wrapper/wscript

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
  ***************************************************************************/
index 60b4ca89d1ce54f90e2a87248f20c75530e89300..517082a569eb22d02402239ca2ec1f145ee890d9 100644 (file)
@@ -60,6 +60,7 @@ def configure(conf):
 
         conf.CHECK_FUNCS('getaddrinfo')
         conf.CHECK_FUNCS('signalfd eventfd timerfd_create')
+        conf.CHECK_FUNCS('bindresvport')
 
         conf.CHECK_FUNCS_IN('bind',
                             'socket',