static int decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg) { struct cmsghdr *cmsg; size_t size, max, i; int overflow = 0; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) continue; size = cmsg->cmsg_len - CMSG_LEN(0); max = sizeof(buffer->data) - wl_buffer_size(buffer); if (size > max || overflow) { overflow = 1; size /= sizeof(int32_t); for (i = 0; i < size; i++) close(((int*)CMSG_DATA(cmsg))[i]); } else if (wl_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) { return -1; } } if (overflow) { errno = EOVERFLOW; return -1; } return 0; }
static int wl_connection_put_fd(struct wl_connection *connection, int32_t fd) { if (wl_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) { connection->want_flush = 1; if (wl_connection_flush(connection) < 0) return -1; } return wl_buffer_put(&connection->fds_out, &fd, sizeof fd); }
static int wl_connection_put_fd(struct wl_connection *connection, int32_t fd) { if (wl_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) if (wl_connection_data(connection, WL_CONNECTION_WRITABLE)) return -1; wl_buffer_put(&connection->fds_out, &fd, sizeof fd); return 0; }
int wl_connection_read(struct wl_connection *connection) { struct iovec iov[2]; struct msghdr msg; char cmsg[CLEN]; int len, count, ret; if (wl_buffer_size(&connection->in) >= sizeof(connection->in.data)) { errno = EOVERFLOW; return -1; } wl_buffer_put_iov(&connection->in, iov, &count); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; msg.msg_control = cmsg; msg.msg_controllen = sizeof cmsg; msg.msg_flags = 0; do { len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT); } while (len < 0 && errno == EINTR); if (len <= 0) return len; ret = decode_cmsg(&connection->fds_in, &msg); if (ret) return -1; connection->in.head += len; return wl_connection_pending_input(connection); }
uint32_t wl_connection_pending_input(struct wl_connection *connection) { return wl_buffer_size(&connection->in); }