Пример #1
0
        /// <summary>
        /// Sends one or more file descriptors over the given socket with SCM_RIGHTS.
        /// </summary>
        /// <param name="sock">The socket handle to use.</param>
        /// <param name="fds">The file descriptors to send. Must contain at least one.</param>
        /// <param name="buffer">The data to send with the message, cannot be null or empty.</param>
        public static void send_fds(int sock, int[] fds, byte[] buffer)
        {
            if (fds == null || fds.Length == 0)
            {
                throw new ArgumentException("At least one file descriptor must be sent");
            }

            if (buffer == null || buffer.Length == 0)
            {
                throw new ArgumentException("The buffer cannot be empty");
            }

            // Create the SCM_RIGHTS control message
            var cmsgbuffer = new byte[Mono.Unix.Native.Syscall.CMSG_SPACE((ulong)fds.Length * sizeof(int))];
            var cmsghdr    = new Mono.Unix.Native.Cmsghdr
            {
                cmsg_len   = (long)Mono.Unix.Native.Syscall.CMSG_LEN((ulong)fds.Length * sizeof(int)),
                cmsg_level = Mono.Unix.Native.UnixSocketProtocol.SOL_SOCKET,
                cmsg_type  = Mono.Unix.Native.UnixSocketControlMessage.SCM_RIGHTS,
            };

            // Create the message header
            var msghdr = new Mono.Unix.Native.Msghdr
            {
                msg_control    = cmsgbuffer,
                msg_controllen = cmsgbuffer.Length,
            };

            cmsghdr.WriteToBuffer(msghdr, 0);

            // Copy in the file handles
            var dataOffset = Mono.Unix.Native.Syscall.CMSG_DATA(msghdr, 0);

            for (var i = 0; i < fds.Length; i++)
            {
                Array.Copy(BitConverter.GetBytes(fds[i]), 0, msghdr.msg_control, dataOffset, sizeof(int));
                dataOffset += sizeof(int);
            }

            // Pin the buffer we are sending
            using (var ptr_buffer1 = new GuardedHandle(buffer))
            {
                // Put the buffer into the IO vector attached to the message
                var iovecs = new[] {
                    new Mono.Unix.Native.Iovec {
                        iov_base = ptr_buffer1.Address,
                        iov_len  = (ulong)buffer.Length,
                    },
                };
                msghdr.msg_iov    = iovecs;
                msghdr.msg_iovlen = 1;

                // Send it
                var ret = Mono.Unix.Native.Syscall.sendmsg(sock, msghdr, 0);
                if (ret < 0)
                {
                    Mono.Unix.UnixMarshal.ThrowExceptionForLastError();
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Reads file descriptors and the message from a SCM_RIGHTS message
        /// </summary>
        /// <returns>The file descriptors and the bytes.</returns>
        /// <param name="handle">The socket to read from.</param>
        public static async Task <List <Tuple <int[], byte[]> > > recv_fds_async(MonitoredHandle handle)
        {
            var buffer = new byte[1024];
            var cmsg   = new byte[1024];
            var msghdr = new Mono.Unix.Native.Msghdr
            {
                msg_control    = cmsg,
                msg_controllen = cmsg.Length,
            };

            long datalen;

            await handle.WaitForReadAsync;

            var res = new List <Tuple <int[], byte[]> >();

            using (var ptr_buffer = new GuardedHandle(buffer))
            {
                var iovec = new [] {
                    new Mono.Unix.Native.Iovec {
                        iov_base = ptr_buffer.Address,
                        iov_len  = (ulong)buffer.Length,
                    },
                };
                msghdr.msg_iov    = iovec;
                msghdr.msg_iovlen = 1;

                DebugHelper.WriteLine("Calling recvmsg");
                while ((datalen = Mono.Unix.Native.Syscall.recvmsg(handle.Handle, msghdr, 0)) != -1)
                {
                    DebugHelper.WriteLine("Called recvmsg: {0}", datalen);
                    if (datalen == 0)
                    {
                        DebugHelper.WriteLine("No more data, stopping recv_fds");
                        handle.Dispose();
                        break;
                    }

                    if (datalen < 0)
                    {
                        Mono.Unix.UnixMarshal.ThrowExceptionForLastError();
                    }

                    // Get the offset of the first message
                    var offset = Mono.Unix.Native.Syscall.CMSG_FIRSTHDR(msghdr);
                    DebugHelper.WriteLine("Called recvmsg, offset: {0}", offset);

                    // Extract the bytes
                    var recvHdr = Mono.Unix.Native.Cmsghdr.ReadFromBuffer(msghdr, offset);
                    //DebugHelper.WriteLine("Buffer has, recvHdr.cmsg_len: {0}", recvHdr.cmsg_len);

                    var data = new byte[datalen];
                    Array.Copy(buffer, data, data.Length);
                    //DebugHelper.WriteLine("Got {0} bytes of data", data.Length);
                    //foreach (var n in data)
                    //    Console.Write("{0}, ", n);
                    //DebugHelper.WriteLine();

                    // See how many bytes are of file descriptors we have
                    var recvDataOffset = Mono.Unix.Native.Syscall.CMSG_DATA(msghdr, offset);
                    //var userData = recvHdr.cmsg_len - (int)Mono.Unix.Native.Syscall.CMSG_LEN(0);
                    var bytes   = recvHdr.cmsg_len - (recvDataOffset - offset);
                    var fdCount = bytes / sizeof(int);
                    var fds     = new int[fdCount];
                    //DebugHelper.WriteLine("Got {0} fds ({1} bytes)", fdCount, bytes);

                    // Extract the file descriptors
                    for (int i = 0; i < fdCount; i++)
                    {
                        fds[i] = BitConverter.ToInt32(msghdr.msg_control, (int)(recvDataOffset + (sizeof(int) * i)));
                        //DebugHelper.WriteLine($"fd[{i}] = {fds[i]}");
                    }

                    //DebugHelper.WriteLine("Read {0} fds and {1} bytes", fds.Length, data.Length);

                    // Check that we only have a single message
                    offset = Mono.Unix.Native.Syscall.CMSG_NXTHDR(msghdr, offset);
                    if (offset != -1)
                    {
                        System.Diagnostics.Trace.WriteLine("WARNING: more than one message detected when reading SCM_RIGHTS, only processing the first one");
                    }


                    res.Add(new Tuple <int[], byte[]>(fds, data));
                }
            }
            var lasterr = Mono.Unix.Native.Stdlib.GetLastError();

            if (res.Count == 0 && datalen < 0 && lasterr != Mono.Unix.Native.Errno.EAGAIN && lasterr != Mono.Unix.Native.Errno.EWOULDBLOCK)
            {
                throw new System.IO.IOException($"Unexpected error code while reading socket: {lasterr}");
            }

            return(res);
        }
Пример #3
0
		public ReceivedMessage RecvMsg ()
		{
//			int r = 0;
//
//			do {
//				r = (int)recvmsg (Handle, bufP, flags);
//			} while (r < 0 && UnixError.ShouldRetry);
//
//			if (r < 0)
//				throw UnixError.GetLastUnixException ();
//
//			return r;

			var buffer2 = new byte[1024*10];
			var cmsg2 = new byte[1024*10];
			var msghdr2 = new Mono.Unix.Native.Msghdr {
				msg_control = cmsg2,
				msg_controllen = cmsg2.Length,
			};
			var result = new ReceivedMessage ();
			fixed (byte* ptr_buffer2 = buffer2) {
				var iovecs2 = new Mono.Unix.Native.Iovec[] {
					new Mono.Unix.Native.Iovec {
						iov_base = (IntPtr) ptr_buffer2,
						iov_len = (ulong) buffer2.Length,
					},
				};
				msghdr2.msg_iov = iovecs2;
				msghdr2.msg_iovlen = 1;
				//System.Console.WriteLine ("recvmsg");
				var ret = Mono.Unix.Native.Syscall.recvmsg (Handle, msghdr2,0);

				if (ret ==-1)  {
					var lastError = Marshal.GetLastWin32Error ();
					System.Console.WriteLine ("Last error " + lastError);
					System.Console.WriteLine ("Description" + Mono.Unix.UnixMarshal.GetErrorDescription((Mono.Unix.Native.Errno)lastError));
					Mono.Unix.UnixMarshal.ThrowExceptionForLastError ();
				}

				result.Read = ret;
				result.Message = buffer2;
			}
				
			#if UNIXFDS
			var fds = new global::System.Collections.Generic.List<int> ();
			for (long offset = Mono.Unix.Native.Syscall.CMSG_FIRSTHDR (msghdr2); offset != -1; offset = Mono.Unix.Native.Syscall.CMSG_NXTHDR (msghdr2, offset)) {
				var recvHdr = Mono.Unix.Native.Cmsghdr.ReadFromBuffer (msghdr2, offset);
				var recvDataOffset = Mono.Unix.Native.Syscall.CMSG_DATA (msghdr2, offset);
				var bytes = recvHdr.cmsg_len - (recvDataOffset - offset);
				//Assert.AreEqual (bytes % sizeof (int), 0);
				var fdCount = bytes / sizeof (int);
				//System.Console.WriteLine("based on struct size, there should be "+fdCount+" fds");
				fixed (byte* ptr = msghdr2.msg_control)
				for (int i = 0; i < fdCount; i++)
					fds.Add (((int*) (ptr + recvDataOffset))[i]);
			}
			if(fds.Count>0)
			{
				result.FileDescriptors = fds.ToArray ();
			}
			#endif
			return result;
		}
Пример #4
0
        /// <summary>
        /// Reads file descriptors and the message from a SCM_RIGHTS message
        /// </summary>
        /// <returns>The file descriptors and the bytes.</returns>
        /// <param name="sock">The socket to read from.</param>
        public static Tuple <int[], byte[]> recv_fds(int sock)
        {
            var buffer = new byte[1024];
            var cmsg   = new byte[1024];
            var msghdr = new Mono.Unix.Native.Msghdr
            {
                msg_control    = cmsg,
                msg_controllen = cmsg.Length,
            };

            long datalen;

            using (var ptr_buffer = new GuardedHandle(buffer))
            {
                var iovec = new[] {
                    new Mono.Unix.Native.Iovec {
                        iov_base = ptr_buffer.Address,
                        iov_len  = (ulong)buffer.Length,
                    },
                };
                msghdr.msg_iov    = iovec;
                msghdr.msg_iovlen = 1;
                DebugHelper.WriteLine("{0}: Calling recvmsg", System.Diagnostics.Process.GetCurrentProcess().Id);
                datalen = Mono.Unix.Native.Syscall.recvmsg(sock, msghdr, 0);
                DebugHelper.WriteLine("{0}: Called recvmsg: {1}", System.Diagnostics.Process.GetCurrentProcess().Id, datalen);
                if (datalen == 0)
                {
                    return(null);
                }
                if (datalen < 0)
                {
                    Mono.Unix.UnixMarshal.ThrowExceptionForLastError();
                }
            }

            // Get the offset of the first message
            var offset = Mono.Unix.Native.Syscall.CMSG_FIRSTHDR(msghdr);

            DebugHelper.WriteLine("{0}: Called recvmsg, offset: {1}", System.Diagnostics.Process.GetCurrentProcess().Id, offset);

            // Extract the bytes
            var recvHdr = Mono.Unix.Native.Cmsghdr.ReadFromBuffer(msghdr, offset);
            //DebugHelper.WriteLine("Buffer has, recvHdr.cmsg_len: {0}", recvHdr.cmsg_len);

            var data = new byte[datalen];

            Array.Copy(buffer, data, data.Length);
            //DebugHelper.WriteLine("Got {0} bytes of data", data.Length);
            //foreach (var n in data)
            //    Console.Write("{0}, ", n);
            //DebugHelper.WriteLine();

            // See how many bytes are of file descriptors we have
            var recvDataOffset = Mono.Unix.Native.Syscall.CMSG_DATA(msghdr, offset);
            //var userData = recvHdr.cmsg_len - (int)Mono.Unix.Native.Syscall.CMSG_LEN(0);
            var bytes   = recvHdr.cmsg_len - (recvDataOffset - offset);
            var fdCount = bytes / sizeof(int);
            var fds     = new int[fdCount];

            //DebugHelper.WriteLine("Got {0} fds ({1} bytes)", fdCount, bytes);

            // Extract the file descriptors
            for (int i = 0; i < fdCount; i++)
            {
                fds[i] = BitConverter.ToInt32(msghdr.msg_control, (int)(recvDataOffset + (sizeof(int) * i)));
                //DebugHelper.WriteLine($"fd[{i}] = {fds[i]}");
            }

            //DebugHelper.WriteLine("Read {0} fds and {1} bytes", fds.Length, data.Length);

            // Check that we only have a single message
            offset = Mono.Unix.Native.Syscall.CMSG_NXTHDR(msghdr, offset);
            if (offset != -1)
            {
                System.Diagnostics.Trace.WriteLine("WARNING: more than one message detected when reading SCM_RIGHTS, only processing the first one");
            }

            return(new Tuple <int[], byte[]>(fds, data));
        }
Пример #5
0
        public ReceivedMessage RecvMsg()
        {
//			int r = 0;
//
//			do {
//				r = (int)recvmsg (Handle, bufP, flags);
//			} while (r < 0 && UnixError.ShouldRetry);
//
//			if (r < 0)
//				throw UnixError.GetLastUnixException ();
//
//			return r;

            var buffer2 = new byte[1024 * 10];
            var cmsg2   = new byte[1024 * 10];
            var msghdr2 = new Mono.Unix.Native.Msghdr {
                msg_control    = cmsg2,
                msg_controllen = cmsg2.Length,
            };
            var result = new ReceivedMessage();

            fixed(byte *ptr_buffer2 = buffer2)
            {
                var iovecs2 = new Mono.Unix.Native.Iovec[] {
                    new Mono.Unix.Native.Iovec {
                        iov_base = (IntPtr)ptr_buffer2,
                        iov_len  = (ulong)buffer2.Length,
                    },
                };

                msghdr2.msg_iov    = iovecs2;
                msghdr2.msg_iovlen = 1;
                //System.Console.WriteLine ("recvmsg");
                var ret = Mono.Unix.Native.Syscall.recvmsg(Handle, msghdr2, 0);

                if (ret == -1)
                {
                    var lastError = Marshal.GetLastWin32Error();
                    System.Console.WriteLine("Last error " + lastError);
                    System.Console.WriteLine("Description" + Mono.Unix.UnixMarshal.GetErrorDescription((Mono.Unix.Native.Errno)lastError));
                    Mono.Unix.UnixMarshal.ThrowExceptionForLastError();
                }

                result.Read    = ret;
                result.Message = buffer2;
            }

                        #if UNIXFDS
            var fds = new global::System.Collections.Generic.List <int> ();
            for (long offset = Mono.Unix.Native.Syscall.CMSG_FIRSTHDR(msghdr2); offset != -1; offset = Mono.Unix.Native.Syscall.CMSG_NXTHDR(msghdr2, offset))
            {
                var recvHdr        = Mono.Unix.Native.Cmsghdr.ReadFromBuffer(msghdr2, offset);
                var recvDataOffset = Mono.Unix.Native.Syscall.CMSG_DATA(msghdr2, offset);
                var bytes          = recvHdr.cmsg_len - (recvDataOffset - offset);
                //Assert.AreEqual (bytes % sizeof (int), 0);
                var fdCount = bytes / sizeof(int);

                //System.Console.WriteLine("based on struct size, there should be "+fdCount+" fds");
                fixed(byte *ptr = msghdr2.msg_control)
                for (int i = 0; i < fdCount; i++)
                {
                    fds.Add(((int *)(ptr + recvDataOffset))[i]);
                }
            }
            if (fds.Count > 0)
            {
                result.FileDescriptors = fds.ToArray();
            }
                        #endif
            return(result);
        }