Merge commit '9dc63482bbeae23dd57b0f885a3fd26b44656844'
[sliver-openvswitch.git] / lib / socket-util.c
index fa55480..7f34ea2 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -132,8 +133,10 @@ rlim_is_finite(rlim_t limit)
 int
 get_max_fds(void)
 {
-    static int max_fds = -1;
-    if (max_fds < 0) {
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+    static int max_fds;
+
+    if (ovsthread_once_start(&once)) {
         struct rlimit r;
         if (!getrlimit(RLIMIT_NOFILE, &r) && rlim_is_finite(r.rlim_cur)) {
             max_fds = r.rlim_cur;
@@ -141,7 +144,9 @@ get_max_fds(void)
             VLOG_WARN("failed to obtain fd limit, defaulting to 1024");
             max_fds = 1024;
         }
+        ovsthread_once_done(&once);
     }
+
     return max_fds;
 }
 
@@ -197,7 +202,8 @@ lookup_hostname(const char *host_name, struct in_addr *addr)
 
     switch (getaddrinfo(host_name, NULL, &hints, &result)) {
     case 0:
-        *addr = ((struct sockaddr_in *) result->ai_addr)->sin_addr;
+        *addr = ALIGNED_CAST(struct sockaddr_in *,
+                             result->ai_addr)->sin_addr;
         freeaddrinfo(result);
         return 0;
 
@@ -802,15 +808,19 @@ error:
 int
 get_null_fd(void)
 {
-    static int null_fd = -1;
-    if (null_fd < 0) {
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+    static int null_fd;
+
+    if (ovsthread_once_start(&once)) {
         null_fd = open("/dev/null", O_RDWR);
         if (null_fd < 0) {
             int error = errno;
             VLOG_ERR("could not open /dev/null: %s", ovs_strerror(error));
-            return -error;
+            null_fd = -error;
         }
+        ovsthread_once_done(&once);
     }
+
     return null_fd;
 }
 
@@ -1318,7 +1328,7 @@ recv_data_and_fds(int sock,
             goto error;
         } else {
             size_t n_fds = (p->cmsg_len - CMSG_LEN(0)) / sizeof *fds;
-            const int *fds_data = (const int *) CMSG_DATA(p);
+            const int *fds_data = ALIGNED_CAST(const int *, CMSG_DATA(p));
 
             ovs_assert(n_fds > 0);
             if (n_fds > SOUTIL_MAX_FDS) {
@@ -1344,3 +1354,42 @@ error:
     *n_fdsp = 0;
     return EPROTO;
 }
+
+/* Calls ioctl() on an AF_INET sock, passing the specified 'command' and
+ * 'arg'.  Returns 0 if successful, otherwise a positive errno value. */
+int
+af_inet_ioctl(unsigned long int command, const void *arg)
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+    static int sock;
+
+    if (ovsthread_once_start(&once)) {
+        sock = socket(AF_INET, SOCK_DGRAM, 0);
+        if (sock < 0) {
+            sock = -errno;
+            VLOG_ERR("failed to create inet socket: %s", ovs_strerror(errno));
+        }
+        ovsthread_once_done(&once);
+    }
+
+    return (sock < 0 ? -sock
+            : ioctl(sock, command, arg) == -1 ? errno
+            : 0);
+}
+
+int
+af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd,
+                    const char *cmd_name)
+{
+    int error;
+
+    ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name);
+    error = af_inet_ioctl(cmd, ifr);
+    if (error) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
+        VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name,
+                    ovs_strerror(error));
+    }
+    return error;
+}
+