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;
void *event_ptr;
struct tevent_fd *fde;
bool optimize_recvfrom;
+ bool netlink;
void *readable_private;
void (*readable_handler)(void *private_data);
* 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);
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 */
ssize_t ret;
int err;
bool retry;
+ int flags = 0;
if (state->dst) {
struct tsocket_address_bsd *bsda =
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 */
{
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,
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;
}
* 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);
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);
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;
}
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;
}
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);