* Blocks until at least one byte of data was sent */
| 71 | * Blocks until at least one byte of data was sent |
| 72 | */ |
| 73 | size_t write_some(const mutable_buffer& Buffers, error& ec) { |
| 74 | auto iov = (iovec*)alloca(sizeof(mutable_buffer) * Buffers.count_chunks()); |
| 75 | size_t NumIovs = 0; |
| 76 | for (auto Buffer = &Buffers; Buffer; Buffer = Buffer->Next) { |
| 77 | iov[NumIovs].iov_base = Buffer->Data.data(); |
| 78 | iov[NumIovs].iov_len = Buffer->Data.size_bytes(); |
| 79 | ++NumIovs; |
| 80 | } |
| 81 | msghdr msg { |
| 82 | .msg_name = nullptr, |
| 83 | .msg_namelen = 0, |
| 84 | .msg_iov = iov, |
| 85 | .msg_iovlen = NumIovs, |
| 86 | }; |
| 87 | |
| 88 | // Setup the ancillary buffer. This is where we will be getting pipe FDs |
| 89 | // We only need 4 bytes for the FD |
| 90 | constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int)); |
| 91 | alignas(cmsghdr) uint8_t AncBuf[CMSG_SIZE]; |
| 92 | |
| 93 | if (Buffers.FD) { |
| 94 | // Enable ancillary buffer |
| 95 | msg.msg_control = AncBuf; |
| 96 | msg.msg_controllen = CMSG_SIZE; |
| 97 | |
| 98 | // Now we need to setup the ancillary buffer data. We are only sending an FD |
| 99 | cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); |
| 100 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| 101 | cmsg->cmsg_level = SOL_SOCKET; |
| 102 | cmsg->cmsg_type = SCM_RIGHTS; |
| 103 | |
| 104 | // We are giving the daemon the write side of the pipe |
| 105 | memcpy(CMSG_DATA(cmsg), Buffers.FD.value(), sizeof(int)); |
| 106 | } |
| 107 | |
| 108 | ssize_t Ret; |
| 109 | do { |
| 110 | Ret = ::sendmsg(FD, &msg, 0); |
| 111 | } while (Ret < 0 && (errno == EINTR || errno == EAGAIN)); |
| 112 | if (Ret < 0) { |
| 113 | ec = error::generic_errno; |
| 114 | return 0; |
| 115 | } |
| 116 | ec = error::success; |
| 117 | return Ret; |
| 118 | } |
| 119 | |
| 120 | private: |
| 121 | static size_t read_some_from_fd(const mutable_buffer& Buffers, error& ec, int FD) { |