Example #1
0
        // Send the two buffers and the FDs using sendmsg(), handle short writes
        public unsafe void Sendmsg(byte[] buffer1, long offset1, long length1,
                                   byte[] buffer2, long offset2, long length2,
                                   DBus.Protocol.UnixFDArray fds)
        {
            //SendmsgShort (buffer1, offset1, length1, buffer2, offset2, length2, fds); return;
            long bytes_overall = (long)length1 + length2;
            long written       = 0;

            while (written < bytes_overall)
            {
                if (written >= length1)
                {
                    long written2 = written - length1;
                    written += SendmsgShort(buffer2, offset2 + written2, length2 - written2, null, 0, 0, written == 0 ? fds : null);
                }
                else
                {
                    written += SendmsgShort(buffer1, offset1 + written, length1 - written, buffer2, offset2, length2, written == 0 ? fds : null);
                }
            }
            if (written != bytes_overall)
            {
                throw new Exception("written != bytes_overall");
            }
        }
Example #2
0
        // Send the two buffers and the FDs using sendmsg(), don't handle short writes
        // length1 + length2 must not be 0
        public unsafe long SendmsgShort(byte[] buffer1, long offset1, long length1,
                                        byte[] buffer2, long offset2, long length2,
                                        DBus.Protocol.UnixFDArray fds)
        {
            //Console.WriteLine ("SendmsgShort (X, {0}, {1}, {2}, {3}, {4}, {5})", offset1, length1, buffer2 == null ? "-" : "Y", offset2, length2, fds == null ? "-" : "" + fds.FDs.Count);
            AssertValidBuffer(buffer1, offset1, length1);
            if (buffer2 == null)
            {
                if (length2 != 0)
                {
                    throw new ArgumentOutOfRangeException("length2", "!= 0 while buffer2 == null");
                }
                offset2 = 0;
            }
            else
            {
                AssertValidBuffer(buffer2, offset2, length2);
            }

            fixed(byte *ptr1 = buffer1, ptr2 = buffer2)
            {
                var iovecs = new Iovec[] {
                    new Iovec {
                        iov_base = (IntPtr)(ptr1 + offset1),
                        iov_len  = (ulong)length1,
                    },
                    new Iovec {
                        iov_base = (IntPtr)(ptr2 + offset2),
                        iov_len  = (ulong)length2,
                    },
                };

                /* Simulate short writes
                 * if (iovecs[0].iov_len == 0) {
                 *      iovecs[1].iov_len = Math.Min (iovecs[1].iov_len, 5);
                 * } else {
                 *      iovecs[0].iov_len = Math.Min (iovecs[0].iov_len, 5);
                 *      iovecs[1].iov_len = 0;
                 * }
                 */
                byte[] cmsg = null;

                // Create copy of FDs to prevent the user from Dispose()ing the
                // FDs in another thread between writing the FDs into the cmsg
                // buffer and calling sendmsg()
                using (var fds2 = fds == null ? null : fds.Clone()) {
                    int fdCount = fds2 == null ? 0 : fds2.FDs.Count;
                    if (fdCount != 0)
                    {
                        // Create one SCM_RIGHTS control message
                        cmsg = new byte[Syscall.CMSG_SPACE((uint)fdCount * sizeof(int))];
                    }
                    var msghdr = new Msghdr {
                        msg_iov        = iovecs,
                        msg_iovlen     = length2 == 0 ? 1 : 2,
                        msg_control    = cmsg,
                        msg_controllen = cmsg == null ? 0 : cmsg.Length,
                    };
                    if (fdCount != 0)
                    {
                        var hdr = new Cmsghdr {
                            cmsg_len   = (long)Syscall.CMSG_LEN((uint)fdCount * sizeof(int)),
                            cmsg_level = UnixSocketProtocol.SOL_SOCKET,
                            cmsg_type  = UnixSocketControlMessage.SCM_RIGHTS,
                        };
                        hdr.WriteToBuffer(msghdr, 0);
                        var dataOffset = Syscall.CMSG_DATA(msghdr, 0);
                        fixed(byte *ptr = cmsg)
                        {
                            for (int i = 0; i < fdCount; i++)
                            {
                                ((int *)(ptr + dataOffset))[i] = fds2.FDs[i].Handle;
                            }
                        }
                    }
                    long r;
                    do
                    {
                        r = Syscall.sendmsg(fd, msghdr, MessageFlags.MSG_NOSIGNAL);
                    } while (UnixMarshal.ShouldRetrySyscall((int)r));
                    if (r < 0)
                    {
                        UnixMarshal.ThrowExceptionForLastError();
                    }
                    if (r == 0)
                    {
                        throw new Exception("sendmsg() returned 0");
                    }
                    return(r);
                }
            }
        }