internal override int Read(byte[] buffer, int offset, int length, UnixFDArray fdArray)
        {
            if (!Connection.UnixFDSupported || fdArray == null)
            {
                return(base.Read(buffer, offset, length, fdArray));
            }

            int read = 0;

            while (read < length)
            {
                int nread = ReadShort(buffer, offset + read, length - read, fdArray);
                if (nread == 0)
                {
                    break;
                }
                read += nread;
            }

            if (read > length)
            {
                throw new Exception();
            }

            return(read);
        }
        internal unsafe override int Read(byte[] buffer, int offset, int count, UnixFDArray fdArray)
        {
            if (!Connection.UnixFDSupported || fdArray == null)
            {
                return(base.Read(buffer, offset, count, fdArray));
            }

            if (count < 0 || offset < 0 || count + offset < count || count + offset > buffer.Length)
            {
                throw new ArgumentException();

                fixed(byte *ptr = buffer)
                {
                    IOVector iov = new IOVector();

                    iov.Base   = ptr + offset;
                    iov.Length = count;

                    msghdr msg = new msghdr();

                    msg.msg_iov    = &iov;
                    msg.msg_iovlen = 1;

                    byte[] cmsg = new byte[CMSG_LEN((ulong)(sizeof(int) * UnixFDArray.MaxFDs))];
                    fixed(byte *cmsgPtr = cmsg)
                    {
                        msg.msg_control    = (IntPtr)(cmsgPtr);
                        msg.msg_controllen = (uint)cmsg.Length;

                        int read = socket.RecvMsg(&msg, 0);

                        for (cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr != null; hdr = CMSG_NXTHDR(&msg, hdr))
                        {
                            if (hdr->cmsg_level != 1)                     //SOL_SOCKET
                            {
                                continue;
                            }
                            if (hdr->cmsg_type != 0x01)                     //SCM_RIGHTS
                            {
                                continue;
                            }
                            int *data    = (int *)CMSG_DATA(hdr);
                            int  fdCount = (int)(((ulong)hdr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
                            for (int i = 0; i < fdCount; i++)
                            {
                                fdArray.FDs.Add(new UnixFD(data[i]));
                            }
                        }

                        if ((msg.msg_flags & 0x08) != 0)                 // MSG_CTRUNC
                        {
                            throw new Exception("Control message truncated");
                        }

                        return(read);
                    }
                }
        }
        // Might return short reads
        unsafe int ReadShort(byte[] buffer, int offset, int length, UnixFDArray fdArray)
        {
            if (length < 0 || offset < 0 || length + offset < length || length + offset > buffer.Length)
            {
                throw new ArgumentException();

                fixed(byte *ptr = buffer, cmsgPtr = cmsgBuffer)
                {
                    var iovecs = new Iovec[] {
                        new Iovec {
                            iov_base = (IntPtr)(ptr + offset),
                            iov_len  = (ulong)length,
                        },
                    };

                    var msghdr = new Msghdr {
                        msg_iov        = iovecs,
                        msg_iovlen     = 1,
                        msg_control    = cmsgBuffer,
                        msg_controllen = cmsgBuffer.Length,
                    };

                    long r;

                    do
                    {
                        r = Syscall.recvmsg((int)SocketHandle, msghdr, 0);
                    } while (UnixMarshal.ShouldRetrySyscall((int)r));

                    for (long cOffset = Syscall.CMSG_FIRSTHDR(msghdr); cOffset != -1; cOffset = Syscall.CMSG_NXTHDR(msghdr, cOffset))
                    {
                        var recvHdr = Cmsghdr.ReadFromBuffer(msghdr, cOffset);
                        if (recvHdr.cmsg_level != UnixSocketProtocol.SOL_SOCKET)
                        {
                            continue;
                        }
                        if (recvHdr.cmsg_type != UnixSocketControlMessage.SCM_RIGHTS)
                        {
                            continue;
                        }
                        var recvDataOffset = Syscall.CMSG_DATA(msghdr, cOffset);
                        var bytes          = recvHdr.cmsg_len - (recvDataOffset - cOffset);
                        var fdCount        = bytes / sizeof(int);
                        for (int i = 0; i < fdCount; i++)
                        {
                            fdArray.FDs.Add(new UnixFD(((int *)(cmsgPtr + recvDataOffset))[i]));
                        }
                    }

                    if ((msghdr.msg_flags & MessageFlags.MSG_CTRUNC) != 0)
                    {
                        throw new Exception("Control message truncated (probably file descriptors lost)");
                    }

                    return((int)r);
                }
        }
Example #4
0
        internal virtual int Read(byte[] buffer, int offset, int count, UnixFDArray fdArray)
        {
            int read = 0;

            while (read < count)
            {
                int nread = stream.Read(buffer, offset + read, count - read);
                if (nread == 0)
                {
                    break;
                }
                read += nread;
            }

            if (read > count)
            {
                throw new Exception();
            }

            return(read);
        }
Example #5
0
        Message ReadMessageReal()
        {
            byte[]      header  = null;
            byte[]      body    = null;
            UnixFDArray fdArray = Connection.UnixFDSupported ? new UnixFDArray() : null;

            int read;

            //16 bytes is the size of the fixed part of the header
            if (readBuffer == null)
            {
                readBuffer = new byte[16];
            }
            byte[] hbuf = readBuffer;

            read = Read(hbuf, 0, 16, fdArray);

            if (read == 0)
            {
                return(null);
            }

            if (read != 16)
            {
                throw new Exception("Header read length mismatch: " + read + " of expected " + "16");
            }

            EndianFlag    endianness = (EndianFlag)hbuf[0];
            MessageReader reader     = new MessageReader(endianness, hbuf);

            //discard endian byte, message type and flags, which we don't care about here
            reader.Seek(3);

            byte version = reader.ReadByte();

            if (version < ProtocolInformation.MinVersion || version > ProtocolInformation.MaxVersion)
            {
                throw new NotSupportedException("Protocol version '" + version.ToString() + "' is not supported");
            }

            if (ProtocolInformation.Verbose)
            {
                if (version != ProtocolInformation.Version)
                {
                    Console.Error.WriteLine("Warning: Protocol version '" + version.ToString() + "' is not explicitly supported but may be compatible");
                }
            }

            uint bodyLength = reader.ReadUInt32();

            //discard serial
            reader.ReadUInt32();
            uint headerLength = reader.ReadUInt32();

            int bodyLen = (int)bodyLength;
            int toRead  = (int)headerLength;

            //we fixup to include the padding following the header
            toRead = ProtocolInformation.Padded(toRead, 8);

            long msgLength = toRead + bodyLen;

            if (msgLength > ProtocolInformation.MaxMessageLength)
            {
                throw new Exception("Message length " + msgLength + " exceeds maximum allowed " + ProtocolInformation.MaxMessageLength + " bytes");
            }

            header = new byte[16 + toRead];
            Array.Copy(hbuf, header, 16);

            read = Read(header, 16, toRead, fdArray);

            if (read != toRead)
            {
                throw new Exception("Message header length mismatch: " + read + " of expected " + toRead);
            }

            //read the body
            if (bodyLen != 0)
            {
                body = new byte[bodyLen];

                read = Read(body, 0, bodyLen, fdArray);

                if (read != bodyLen)
                {
                    throw new Exception("Message body length mismatch: " + read + " of expected " + bodyLen);
                }
            }

            Message msg = Message.FromReceivedBytes(Connection, header, body, fdArray);

            return(msg);
        }