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); } }
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); }
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); }