Revert "tsocket_bsd use sendmsg/recvmsg"
[metze/samba/wip.git] / lib / tsocket / tsocket_bsd.c
index f1ece7595e0953c859116967675e3e4c3278d304..7ebc564692d79b0edfb6fac6733a5a266819e8e1 100644 (file)
@@ -132,6 +132,43 @@ static int tsocket_bsd_common_prepare_fd(int fd, bool high_fd)
        return -1;
 }
 
+#ifdef HAVE_LINUX_RTNETLINK_H
+/**
+ * Get the amount of pending bytes from a netlink socket
+ *
+ * For some reason netlink sockets don't support querying the amount of pending
+ * data via ioctl with FIONREAD, which is what we use in tsocket_bsd_pending()
+ * below.
+ *
+ * We know we are on Linux as we're using netlink, which means we have a working
+ * MSG_TRUNC flag to recvmsg() as well, so we use that together with MSG_PEEK.
+ **/
+static ssize_t tsocket_bsd_netlink_pending(int fd)
+{
+       struct iovec iov;
+       struct msghdr msg;
+       char buf[1];
+
+       iov = (struct iovec) {
+               .iov_base = buf,
+               .iov_len = sizeof(buf)
+       };
+
+       msg = (struct msghdr) {
+               .msg_iov = &iov,
+               .msg_iovlen = 1
+       };
+
+       return recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC);
+}
+#else
+static ssize_t tsocket_bsd_netlink_pending(int fd)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
+
 static ssize_t tsocket_bsd_pending(int fd)
 {
        int ret, error;
@@ -640,6 +677,7 @@ struct tdgram_bsd {
        void *event_ptr;
        struct tevent_fd *fde;
        bool optimize_recvfrom;
+       bool netlink;
 
        void *readable_private;
        void (*readable_handler)(void *private_data);
@@ -855,7 +893,7 @@ static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
                 * recvfrom if the caller asked for it.
                 *
                 * This is needed because in most cases
-                * we preferr to flush send buffers before
+                * we prefer to flush send buffers before
                 * receiving incoming requests.
                 */
                tdgram_bsd_recvfrom_handler(req);
@@ -892,7 +930,12 @@ static void tdgram_bsd_recvfrom_handler(void *private_data)
        int err;
        bool retry;
 
-       ret = tsocket_bsd_pending(bsds->fd);
+       if (bsds->netlink) {
+               ret = tsocket_bsd_netlink_pending(bsds->fd);
+       } else {
+               ret = tsocket_bsd_pending(bsds->fd);
+       }
+
        if (state->first_try && ret == 0) {
                state->first_try = false;
                /* retry later */
@@ -1071,6 +1114,7 @@ static void tdgram_bsd_sendto_handler(void *private_data)
        ssize_t ret;
        int err;
        bool retry;
+       int flags = 0;
 
        if (state->dst) {
                struct tsocket_address_bsd *bsda =
@@ -1081,7 +1125,10 @@ static void tdgram_bsd_sendto_handler(void *private_data)
                sa_socklen = bsda->sa_socklen;
        }
 
-       ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_socklen);
+#ifdef MSG_NOSIGNAL
+       flags |= MSG_NOSIGNAL;
+#endif
+       ret = sendto(bsds->fd, state->buf, state->len, flags, sa, sa_socklen);
        err = tsocket_bsd_error_from_errno(ret, errno, &retry);
        if (retry) {
                /* retry later */
@@ -1395,6 +1442,11 @@ int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
 {
        struct tdgram_context *dgram;
        struct tdgram_bsd *bsds;
+#ifdef HAVE_LINUX_RTNETLINK_H
+       int result;
+       struct sockaddr sa;
+       socklen_t sa_len = sizeof(struct sockaddr);
+#endif
 
        dgram = tdgram_context_create(mem_ctx,
                                      &tdgram_bsd_ops,
@@ -1409,6 +1461,18 @@ int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
        talloc_set_destructor(bsds, tdgram_bsd_destructor);
 
        *_dgram = dgram;
+
+#ifdef HAVE_LINUX_RTNETLINK_H
+       /*
+        * Try to determine the protocol family and remember if it's
+        * AF_NETLINK. We don't care if this fails.
+        */
+       result = getsockname(fd, &sa, &sa_len);
+       if (result == 0 && sa.sa_family == AF_NETLINK) {
+               bsds->netlink = true;
+       }
+#endif
+
        return 0;
 }
 
@@ -1746,7 +1810,7 @@ static struct tevent_req *tstream_bsd_readv_send(TALLOC_CTX *mem_ctx,
                 * readv if the caller asked for it.
                 *
                 * This is needed because in most cases
-                * we preferr to flush send buffers before
+                * we prefer to flush send buffers before
                 * receiving incoming requests.
                 */
                tstream_bsd_readv_handler(req);
@@ -1925,8 +1989,21 @@ static void tstream_bsd_writev_handler(void *private_data)
        int err;
        int _count;
        bool ok, retry;
-
-       ret = writev(bsds->fd, state->vector, state->count);
+       struct msghdr msg;
+       int flags = 0;
+
+       msg.msg_name = NULL;           /* optional address */
+       msg.msg_namelen = 0;           /* size of address */
+       msg.msg_iov = state->vector;   /* scatter/gather array */
+       msg.msg_iovlen = state->count; /* # elements in msg_iov */
+       msg.msg_control = NULL;        /* ancillary data, see below */
+       msg.msg_controllen = 0;        /* ancillary data buffer len */
+       msg.msg_flags = 0;             /* flags on received message */
+
+#ifdef MSG_NOSIGNAL
+       flags |= MSG_NOSIGNAL;
+#endif
+       ret = sendmsg(bsds->fd, &msg, flags);
        if (ret == 0) {
                /* propagate end of file */
                tevent_req_error(req, EPIPE);
@@ -2114,8 +2191,6 @@ static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
                talloc_get_type_abort(remote->private_data,
                struct tsocket_address_bsd);
        int ret;
-       int err;
-       bool retry;
        bool do_bind = false;
        bool do_reuseaddr = false;
        bool do_ipv6only = false;
@@ -2256,12 +2331,11 @@ static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
        }
 
        ret = connect(state->fd, &rbsda->u.sa, rbsda->sa_socklen);
-       err = tsocket_bsd_error_from_errno(ret, errno, &retry);
-       if (retry) {
-               /* retry later */
-               goto async;
-       }
-       if (tevent_req_error(req, err)) {
+       if (ret == -1) {
+               if (errno == EINPROGRESS) {
+                       goto async;
+               }
+               tevent_req_error(req, errno);
                goto post;
        }
 
@@ -2270,10 +2344,14 @@ static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
                goto post;
        }
 
-       ret = getsockname(state->fd, &lrbsda->u.sa, &lrbsda->sa_socklen);
-       if (ret == -1) {
-               tevent_req_error(req, errno);
-               goto post;
+       if (lrbsda != NULL) {
+               ret = getsockname(state->fd,
+                                 &lrbsda->u.sa,
+                                 &lrbsda->sa_socklen);
+               if (ret == -1) {
+                       tevent_req_error(req, errno);
+                       goto post;
+               }
        }
 
        tevent_req_done(req);