Add Nicira extension for remote command execution.
[sliver-openvswitch.git] / lib / socket-util.c
index ca08de5..d8ae179 100644 (file)
@@ -41,6 +41,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/resource.h>
 #include <sys/un.h>
 #include <unistd.h>
 #include "fatal-signal.h"
@@ -68,6 +69,26 @@ set_nonblocking(int fd)
     }
 }
 
+/* Returns the maximum valid FD value, plus 1. */
+int
+get_max_fds(void)
+{
+    static int max_fds = -1;
+    if (max_fds < 0) {
+        struct rlimit r;
+        if (!getrlimit(RLIMIT_NOFILE, &r)
+            && r.rlim_cur != RLIM_INFINITY
+            && r.rlim_cur != RLIM_SAVED_MAX
+            && r.rlim_cur != RLIM_SAVED_CUR) {
+            max_fds = r.rlim_cur;
+        } else {
+            VLOG_WARN("failed to obtain fd limit, defaulting to 1024");
+            max_fds = 1024;
+        }
+    }
+    return max_fds;
+}
+
 /* Translates 'host_name', which may be a DNS name or an IP address, into a
  * numeric IP address in '*addr'.  Returns 0 if successful, otherwise a
  * positive errno value. */
@@ -170,6 +191,24 @@ drain_rcvbuf(int fd)
     return 0;
 }
 
+/* Reads and discards up to 'n' datagrams from 'fd', stopping as soon as no
+ * more data can be immediately read.  ('fd' should therefore be in
+ * non-blocking mode.)*/
+void
+drain_fd(int fd, size_t n_packets)
+{
+    for (; n_packets > 0; n_packets--) {
+        /* 'buffer' only needs to be 1 byte long in most circumstances.  This
+         * size is defensive against the possibility that we someday want to
+         * use a Linux tap device without TUN_NO_PI, in which case a buffer
+         * smaller than sizeof(struct tun_pi) will give EINVAL on read. */
+        char buffer[128];
+        if (read(fd, buffer, sizeof buffer) <= 0) {
+            break;
+        }
+    }
+}
+
 /* Stores in '*un' a sockaddr_un that refers to file 'name'.  Stores in
  * '*un_len' the size of the sockaddr_un. */
 static void
@@ -201,6 +240,10 @@ make_unix_socket(int style, bool nonblock, bool passcred UNUSED,
         return -errno;
     }
 
+    /* Set nonblocking mode right away, if we want it.  This prevents blocking
+     * in connect(), if connect_path != NULL.  (In turn, that's a corner case:
+     * it will only happen if style is SOCK_STREAM or SOCK_SEQPACKET, and only
+     * if a backlog of un-accepted connections has built up in the kernel.)  */
     if (nonblock) {
         int flags = fcntl(fd, F_GETFL, 0);
         if (flags == -1) {