Пример #1
0
        // 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);
                }
        }
Пример #2
0
        public unsafe void SendMsgRecvMsg()
        {
            WithSocketPair((so1, so2) => {
                long ret;
                var buffer1             = new byte[] { 42, 43, 44 };
                fixed(byte *ptr_buffer1 = buffer1)
                {
                    var iovecs1 = new Iovec[] {
                        new Iovec {
                            iov_base = (IntPtr)ptr_buffer1,
                            iov_len  = (ulong)buffer1.Length,
                        },
                    };
                    var msghdr1 = new Msghdr {
                        msg_iov    = iovecs1,
                        msg_iovlen = 1,
                    };
                    ret = Syscall.sendmsg(so1, msghdr1, 0);
                }
                if (ret < 0)
                {
                    UnixMarshal.ThrowExceptionForLastError();
                }

                var buffer2             = new byte[1024];
                fixed(byte *ptr_buffer2 = buffer2)
                {
                    var iovecs2 = new Iovec[] {
                        new Iovec {
                            iov_base = (IntPtr)ptr_buffer2,
                            iov_len  = (ulong)buffer2.Length,
                        },
                    };
                    var msghdr2 = new Msghdr {
                        msg_iov    = iovecs2,
                        msg_iovlen = 1,
                    };
                    ret = Syscall.recvmsg(so2, msghdr2, 0);
                }
                if (ret < 0)
                {
                    UnixMarshal.ThrowExceptionForLastError();
                }

                Assert.AreEqual(buffer1.Length, ret);
                for (int i = 0; i < buffer1.Length; i++)
                {
                    Assert.AreEqual(buffer1[i], buffer2[i]);
                }
            });
        }
Пример #3
0
        static bool CheckAvailable()
        {
            var msghdr = new Msghdr {
                msg_iov    = new Iovec[] {},
                msg_iovlen = 0,
            };

            // sendmsg() should return EBADFD because fd == -1
            // If sendmsg() is not available (e.g. because Mono.Posix is too
            // old or this is on a system without sendmsg()), Syscall.sendmsg()
            // will throw an exception
            Syscall.sendmsg(-1, msghdr, 0);
            return(true);
        }
Пример #4
0
        /// <summary>
        /// Receive the message from the socket pooling service.
        /// </summary>
        /// <param name="socket">Socket.</param>
        /// <param name="size">Size of the message.</param>
        /// <returns>Message received.</returns>
        internal static unsafe SockPoolMessage ReceiveMessage(
            Socket socket,
            int size)
        {
            var buffer = new byte[size];

            fixed(byte *bufferPtr = &buffer[0])
            {
                var data = new[]
                {
                    new Iovec
                    {
                        iov_base = (IntPtr)bufferPtr,
                        iov_len  = (ulong)buffer.Length
                    }
                };
                var controlBuffer = new byte[Syscall.CMSG_SPACE(sizeof(int))];
                var message       = new Msghdr
                {
                    msg_iov        = data,
                    msg_iovlen     = data.Length,
                    msg_control    = controlBuffer,
                    msg_controllen = controlBuffer.Length
                };

                Syscall.recvmsg(socket.Handle.ToInt32(), message, 0);

                var result = new SockPoolMessage
                {
                    Buffer = buffer
                };

                // Parse the control part of the message if exists. This may
                // contain a socket handle
                if (message.msg_controllen > 0)
                {
                    var control = Cmsghdr.ReadFromBuffer(message, 0);
                    var offset  = (int)Syscall.CMSG_DATA(message, 0);
                    result.Handle =
                        new IntPtr(BitConverter.ToInt32(controlBuffer, offset)
                                   );
                }

                return(result);
            }
        }
Пример #5
0
		public unsafe void ControlMsg (bool useMultipleControlMessages)
		{
			// Create two socket pairs and send inner_so1 and inner_so2 over the other socket pair using SCM_RIGHTS
			WithSocketPair ((inner_so1, inner_so2) => {
				WithSocketPair ((so1, so2) => {
					byte[] cmsg;
					Msghdr msghdr1;
					long offset;
					if (useMultipleControlMessages) {
						// Create two SCM_RIGHTS control messages
						cmsg = new byte[2 * Syscall.CMSG_SPACE (sizeof (int))];
						var hdr = new Cmsghdr {
							cmsg_len = (long) Syscall.CMSG_LEN (sizeof (int)),
							cmsg_level = UnixSocketProtocol.SOL_SOCKET,
							cmsg_type = UnixSocketControlMessage.SCM_RIGHTS,
						};
						msghdr1 = new Msghdr {
							msg_control = cmsg,
							msg_controllen = cmsg.Length,
						};
						offset = 0;
						hdr.WriteToBuffer (msghdr1, offset);
						var dataOffset = Syscall.CMSG_DATA (msghdr1, offset);
						fixed (byte* ptr = msghdr1.msg_control) {
							((int*) (ptr + dataOffset))[0] = inner_so1;
						}
						offset = (long) Syscall.CMSG_SPACE (sizeof (int));
						hdr.WriteToBuffer (msghdr1, offset);
						dataOffset = Syscall.CMSG_DATA (msghdr1, offset);
						fixed (byte* ptr = msghdr1.msg_control) {
							((int*) (ptr + dataOffset))[0] = inner_so2;
						}
					} else {
						// Create one SCM_RIGHTS control message
						cmsg = new byte[Syscall.CMSG_SPACE (2 * sizeof (int))];
						var hdr = new Cmsghdr {
							cmsg_len = (long) Syscall.CMSG_LEN (2 * sizeof (int)),
							cmsg_level = UnixSocketProtocol.SOL_SOCKET,
							cmsg_type = UnixSocketControlMessage.SCM_RIGHTS,
						};
						msghdr1 = new Msghdr {
							msg_control = cmsg,
							msg_controllen = cmsg.Length,
						};
						offset = 0;
						hdr.WriteToBuffer (msghdr1, offset);
						var dataOffset = Syscall.CMSG_DATA (msghdr1, offset);
						fixed (byte* ptr = msghdr1.msg_control) {
							((int*) (ptr + dataOffset))[0] = inner_so1;
							((int*) (ptr + dataOffset))[1] = inner_so2;
						}
					}

					long ret;
					var buffer1 = new byte[] { 42, 43, 44 };
					fixed (byte* ptr_buffer1 = buffer1) {
						var iovecs1 = new Iovec[] {
							new Iovec {
								iov_base = (IntPtr) ptr_buffer1,
								iov_len = (ulong) buffer1.Length,
							},
						};
						msghdr1.msg_iov = iovecs1;
						msghdr1.msg_iovlen = 1;
						// Send message twice
						ret = Syscall.sendmsg (so1, msghdr1, 0);
						if (ret < 0)
							UnixMarshal.ThrowExceptionForLastError ();
						ret = Syscall.sendmsg (so1, msghdr1, 0);
						if (ret < 0)
							UnixMarshal.ThrowExceptionForLastError ();
					}

					// Receive without control message buffer
					var buffer2 = new byte[1024];
					var msghdr2 = new Msghdr { };
					fixed (byte* ptr_buffer2 = buffer2) {
						var iovecs2 = new Iovec[] {
							new Iovec {
								iov_base = (IntPtr) ptr_buffer2,
								iov_len = (ulong) buffer2.Length,
							},
						};
						msghdr2.msg_iov = iovecs2;
						msghdr2.msg_iovlen = 1;
						ret = Syscall.recvmsg (so2, msghdr2, 0);
					}
					if (ret < 0)
						UnixMarshal.ThrowExceptionForLastError ();

					if (useMultipleControlMessages) // This assertion fails on OSX for some reason
						Assert.IsTrue ((msghdr2.msg_flags & MessageFlags.MSG_CTRUNC) != 0); // Control message has been truncated

					Assert.AreEqual (buffer1.Length, ret);
					for (int i = 0; i < buffer1.Length; i++)
						Assert.AreEqual (buffer1[i], buffer2[i]);

					// Receive with control message buffer
					buffer2 = new byte[1024];
					var cmsg2 = new byte[1024];
					msghdr2 = new Msghdr {
						msg_control = cmsg2,
						msg_controllen = cmsg2.Length,
					};
					fixed (byte* ptr_buffer2 = buffer2) {
						var iovecs2 = new Iovec[] {
							new Iovec {
								iov_base = (IntPtr) ptr_buffer2,
								iov_len = (ulong) buffer2.Length,
							},
						};
						msghdr2.msg_iov = iovecs2;
						msghdr2.msg_iovlen = 1;
						ret = Syscall.recvmsg (so2, msghdr2, 0);
					}
					if (ret < 0)
						UnixMarshal.ThrowExceptionForLastError ();

					var fds = new global::System.Collections.Generic.List<int> ();
					for (offset = Syscall.CMSG_FIRSTHDR (msghdr2); offset != -1; offset = Syscall.CMSG_NXTHDR (msghdr2, offset)) {
						var recvHdr = Cmsghdr.ReadFromBuffer (msghdr2, offset);
						var recvDataOffset = Syscall.CMSG_DATA (msghdr2, offset);
						var bytes = recvHdr.cmsg_len - (recvDataOffset - offset);
						Assert.AreEqual (bytes % sizeof (int), 0);
						var fdCount = bytes / sizeof (int);
						fixed (byte* ptr = msghdr2.msg_control)
							for (int i = 0; i < fdCount; i++)
								fds.Add (((int*) (ptr + recvDataOffset))[i]);
					}
					try {
						Assert.IsTrue ((msghdr2.msg_flags & MessageFlags.MSG_CTRUNC) == 0); // Control message has not been truncated

						Assert.AreEqual (buffer1.Length, ret);
						for (int i = 0; i < buffer1.Length; i++)
							Assert.AreEqual (buffer1[i], buffer2[i]);

						Assert.AreEqual (fds.Count, 2);

						// Send message over the first received fd and receive it over inner_so2
						var buffer3 = new byte[] { 16, 17 };
						ret = Syscall.send (fds[0], buffer3, (ulong) buffer3.Length, 0);
						if (ret < 0)
							UnixMarshal.ThrowExceptionForLastError ();

						var buffer4 = new byte[1024];
						ret = Syscall.recv (inner_so2, buffer4, (ulong) buffer4.Length, 0);
						if (ret < 0)
							UnixMarshal.ThrowExceptionForLastError ();

						Assert.AreEqual (buffer3.Length, ret);
						for (int i = 0; i < buffer3.Length; i++)
							Assert.AreEqual (buffer3[i], buffer4[i]);

						// Send message over inner_so1 and receive it second received fd
						var buffer5 = new byte[] { 10, 40, 0, 1 };
						ret = Syscall.send (inner_so1, buffer5, (ulong) buffer5.Length, 0);
						if (ret < 0)
							UnixMarshal.ThrowExceptionForLastError ();

						var buffer6 = new byte[1024];
						ret = Syscall.recv (fds[1], buffer6, (ulong) buffer6.Length, 0);
						if (ret < 0)
							UnixMarshal.ThrowExceptionForLastError ();

						Assert.AreEqual (buffer5.Length, ret);
						for (int i = 0; i < buffer5.Length; i++)
							Assert.AreEqual (buffer5[i], buffer6[i]);
					} finally {
						foreach (var fd in fds)
							if (Syscall.close (fd) < 0)
								UnixMarshal.ThrowExceptionForLastError ();
					}
				});
			});
		}
Пример #6
0
		public unsafe void SendMsgRecvMsgAddress ()
		{
			WithSockets (UnixAddressFamily.AF_INET, UnixSocketType.SOCK_DGRAM, UnixSocketProtocol.IPPROTO_UDP, (so1, so2) => {
				// Bind UDP socket so1 to 127.0.0.1 with dynamic port
				var address = new SockaddrIn {
					sin_family = UnixAddressFamily.AF_INET,
					sin_port = Syscall.htons (0),
					sin_addr = new InAddr (127, 0, 0, 1),
				};
				if (Syscall.bind (so1, address) < 0)
					UnixMarshal.ThrowExceptionForLastError ();

				// Get actual port number using getsockname()
				var actualAddress = new SockaddrIn ();
				if (Syscall.getsockname (so1, actualAddress) < 0)
					UnixMarshal.ThrowExceptionForLastError ();
				Assert.AreEqual (actualAddress.sa_family, UnixAddressFamily.AF_INET);
				var port = Syscall.ntohs (actualAddress.sin_port);
				Assert.IsTrue (port != 0);


				var remoteAddress = new SockaddrIn {
					sin_family = UnixAddressFamily.AF_INET,
					sin_port = Syscall.htons (port),
					sin_addr = new InAddr (127, 0, 0, 1),
				};

				// Send and receive a few bytes
				long ret;
				var buffer1 = new byte[] { 42, 43, 44 };
				fixed (byte* ptr_buffer1 = buffer1) {
					var iovecs1 = new Iovec[] {
						new Iovec {
							iov_base = (IntPtr) ptr_buffer1,
							iov_len = (ulong) buffer1.Length,
						},
					};
					var msghdr1 = new Msghdr {
						msg_name = remoteAddress,
						msg_iov = iovecs1,
						msg_iovlen = 1,
					};
					ret = Syscall.sendmsg (so2, msghdr1, 0);
					msghdr1.msg_name = remoteAddress.ToSockaddrStorage ();
					if (ret >= 0)
						ret = Syscall.sendmsg (so2, msghdr1, 0);
				}
				if (ret < 0)
					UnixMarshal.ThrowExceptionForLastError ();

				var senderAddress = new SockaddrIn ();
				var senderAddressStorage = new SockaddrStorage ();
				var buffer2 = new byte[1024];
				var buffer3 = new byte[1024];
				fixed (byte* ptr_buffer2 = buffer2, ptr_buffer3 = buffer3) {
					var iovecs2 = new Iovec[] {
						new Iovec {
							iov_base = (IntPtr) ptr_buffer2,
							iov_len = (ulong) buffer2.Length,
						},
					};
					var msghdr2 = new Msghdr {
						msg_name = senderAddress,
						msg_iov = iovecs2,
						msg_iovlen = 1,
					};
					ret = Syscall.recvmsg (so1, msghdr2, 0);
					msghdr2.msg_name = senderAddressStorage;
					iovecs2[0].iov_base = (IntPtr) ptr_buffer3;
					if (ret >= 0)
						ret = Syscall.recvmsg (so1, msghdr2, 0);
				}
				if (ret < 0)
					UnixMarshal.ThrowExceptionForLastError ();
				Assert.AreEqual (senderAddress.sa_family, UnixAddressFamily.AF_INET);
				Assert.AreEqual (senderAddress.sin_addr, new InAddr (127, 0, 0, 1));
				var senderAddress2 = SockaddrIn.FromSockaddrStorage (senderAddressStorage);
				Assert.AreEqual (senderAddress2.sa_family, UnixAddressFamily.AF_INET);
				Assert.AreEqual (senderAddress2.sin_addr, new InAddr (127, 0, 0, 1));

				Assert.AreEqual (buffer1.Length, ret);
				for (int i = 0; i < buffer1.Length; i++)
					Assert.AreEqual (buffer1[i], buffer2[i]);
				for (int i = 0; i < buffer1.Length; i++)
					Assert.AreEqual (buffer1[i], buffer3[i]);
			});
		}
Пример #7
0
		public unsafe void SendMsgRecvMsg ()
		{
			WithSocketPair ((so1, so2) => {
				long ret;
				var buffer1 = new byte[] { 42, 43, 44 };
				fixed (byte* ptr_buffer1 = buffer1) {
					var iovecs1 = new Iovec[] {
						new Iovec {
							iov_base = (IntPtr) ptr_buffer1,
							iov_len = (ulong) buffer1.Length,
						},
					};
					var msghdr1 = new Msghdr {
						msg_iov = iovecs1,
						msg_iovlen = 1,
					};
					ret = Syscall.sendmsg (so1, msghdr1, 0);
				}
				if (ret < 0)
					UnixMarshal.ThrowExceptionForLastError ();

				var buffer2 = new byte[1024];
				fixed (byte* ptr_buffer2 = buffer2) {
					var iovecs2 = new Iovec[] {
						new Iovec {
							iov_base = (IntPtr) ptr_buffer2,
							iov_len = (ulong) buffer2.Length,
						},
					};
					var msghdr2 = new Msghdr {
						msg_iov = iovecs2,
						msg_iovlen = 1,
					};
					ret = Syscall.recvmsg (so2, msghdr2, 0);
				}
				if (ret < 0)
					UnixMarshal.ThrowExceptionForLastError ();

				Assert.AreEqual (buffer1.Length, ret);
				for (int i = 0; i < buffer1.Length; i++)
					Assert.AreEqual (buffer1[i], buffer2[i]);
			});
		}
Пример #8
0
        /// <summary>
        /// Send the message to the socket pooling service.
        /// </summary>
        /// <param name="socket">Socket.</param>
        /// <param name="message">Message.</param>
        internal static unsafe void SendMessage(
            Socket socket,
            SockPoolMessage message)
        {
            fixed(byte *bufferPtr = &message.Buffer[0])
            {
                var data = new[]
                {
                    new Iovec
                    {
                        iov_base = (IntPtr)bufferPtr,
                        iov_len  = (ulong)message.Buffer.Length
                    }
                };
                var msghdr = new Msghdr
                {
                    msg_iovlen = data.Length,
                    msg_iov    = data
                };

                if (message.Handle != IntPtr.Zero)
                {
                    msghdr.msg_control = new byte[Syscall.CMSG_SPACE(sizeof(int))];
                    var control = new Cmsghdr();
                    control.cmsg_len             = msghdr.msg_controllen
                                                 = msghdr.msg_control.Length;
                    control.cmsg_level           = UnixSocketProtocol.SOL_SOCKET;
                    control.cmsg_type            = UnixSocketControlMessage.SCM_RIGHTS;
                    control.WriteToBuffer(msghdr, 0);

                    var handleBuffer
                        = BitConverter.GetBytes(message.Handle.ToInt32());
                    Buffer.BlockCopy(
                        handleBuffer,
                        0,
                        msghdr.msg_control,
                        (int)Syscall.CMSG_SPACE(0),
                        sizeof(int)
                        );
                }

                var rc = -1L;

                do
                {
                    rc = Syscall.sendmsg(socket.Handle.ToInt32(), msghdr, 0);
                    if (rc == -1)
                    {
                        throw new Exception(
                                  "Failed to send a message to the sockpool socket" +
                                  $", rc={Syscall.GetLastError()}"
                                  );
                    }
                    else if (rc > 0)
                    {
                        data[0].iov_base += (int)rc;
                        data[0].iov_len  -= (ulong)rc;

                        // Reach the end of the buffer
                        if (data[0].iov_len == 0)
                        {
                            break;
                        }
                    }
                }while(rc != 0);
            }
        }
Пример #9
0
        public unsafe void ControlMsg(bool useMultipleControlMessages)
        {
            // Create two socket pairs and send inner_so1 and inner_so2 over the other socket pair using SCM_RIGHTS
            WithSocketPair((inner_so1, inner_so2) => {
                WithSocketPair((so1, so2) => {
                    byte[] cmsg;
                    Msghdr msghdr1;
                    long offset;
                    if (useMultipleControlMessages)
                    {
                        // Create two SCM_RIGHTS control messages
                        cmsg    = new byte[2 * Syscall.CMSG_SPACE(sizeof(int))];
                        var hdr = new Cmsghdr {
                            cmsg_len   = (long)Syscall.CMSG_LEN(sizeof(int)),
                            cmsg_level = UnixSocketProtocol.SOL_SOCKET,
                            cmsg_type  = UnixSocketControlMessage.SCM_RIGHTS,
                        };
                        msghdr1 = new Msghdr {
                            msg_control    = cmsg,
                            msg_controllen = cmsg.Length,
                        };
                        offset = 0;
                        hdr.WriteToBuffer(msghdr1, offset);
                        var dataOffset  = Syscall.CMSG_DATA(msghdr1, offset);
                        fixed(byte *ptr = msghdr1.msg_control)
                        {
                            ((int *)(ptr + dataOffset))[0] = inner_so1;
                        }
                        offset = (long)Syscall.CMSG_SPACE(sizeof(int));
                        hdr.WriteToBuffer(msghdr1, offset);
                        dataOffset      = Syscall.CMSG_DATA(msghdr1, offset);
                        fixed(byte *ptr = msghdr1.msg_control)
                        {
                            ((int *)(ptr + dataOffset))[0] = inner_so2;
                        }
                    }
                    else
                    {
                        // Create one SCM_RIGHTS control message
                        cmsg    = new byte[Syscall.CMSG_SPACE(2 * sizeof(int))];
                        var hdr = new Cmsghdr {
                            cmsg_len   = (long)Syscall.CMSG_LEN(2 * sizeof(int)),
                            cmsg_level = UnixSocketProtocol.SOL_SOCKET,
                            cmsg_type  = UnixSocketControlMessage.SCM_RIGHTS,
                        };
                        msghdr1 = new Msghdr {
                            msg_control    = cmsg,
                            msg_controllen = cmsg.Length,
                        };
                        offset = 0;
                        hdr.WriteToBuffer(msghdr1, offset);
                        var dataOffset  = Syscall.CMSG_DATA(msghdr1, offset);
                        fixed(byte *ptr = msghdr1.msg_control)
                        {
                            ((int *)(ptr + dataOffset))[0] = inner_so1;
                            ((int *)(ptr + dataOffset))[1] = inner_so2;
                        }
                    }

                    long ret;
                    var buffer1             = new byte[] { 42, 43, 44 };
                    fixed(byte *ptr_buffer1 = buffer1)
                    {
                        var iovecs1 = new Iovec[] {
                            new Iovec {
                                iov_base = (IntPtr)ptr_buffer1,
                                iov_len  = (ulong)buffer1.Length,
                            },
                        };
                        msghdr1.msg_iov    = iovecs1;
                        msghdr1.msg_iovlen = 1;
                        // Send message twice
                        ret = Syscall.sendmsg(so1, msghdr1, 0);
                        if (ret < 0)
                        {
                            UnixMarshal.ThrowExceptionForLastError();
                        }
                        ret = Syscall.sendmsg(so1, msghdr1, 0);
                        if (ret < 0)
                        {
                            UnixMarshal.ThrowExceptionForLastError();
                        }
                    }

                    // Receive without control message buffer
                    var buffer2             = new byte[1024];
                    var msghdr2             = new Msghdr {
                    };
                    fixed(byte *ptr_buffer2 = buffer2)
                    {
                        var iovecs2 = new Iovec[] {
                            new Iovec {
                                iov_base = (IntPtr)ptr_buffer2,
                                iov_len  = (ulong)buffer2.Length,
                            },
                        };
                        msghdr2.msg_iov    = iovecs2;
                        msghdr2.msg_iovlen = 1;
                        ret = Syscall.recvmsg(so2, msghdr2, 0);
                    }
                    if (ret < 0)
                    {
                        UnixMarshal.ThrowExceptionForLastError();
                    }

                    if (useMultipleControlMessages)                                        // This assertion fails on OSX for some reason
                    {
                        Assert.IsTrue((msghdr2.msg_flags & MessageFlags.MSG_CTRUNC) != 0); // Control message has been truncated
                    }
                    Assert.AreEqual(buffer1.Length, ret);
                    for (int i = 0; i < buffer1.Length; i++)
                    {
                        Assert.AreEqual(buffer1[i], buffer2[i]);
                    }

                    // Receive with control message buffer
                    buffer2   = new byte[1024];
                    var cmsg2 = new byte[1024];
                    msghdr2   = new Msghdr {
                        msg_control    = cmsg2,
                        msg_controllen = cmsg2.Length,
                    };
                    fixed(byte *ptr_buffer2 = buffer2)
                    {
                        var iovecs2 = new Iovec[] {
                            new Iovec {
                                iov_base = (IntPtr)ptr_buffer2,
                                iov_len  = (ulong)buffer2.Length,
                            },
                        };
                        msghdr2.msg_iov    = iovecs2;
                        msghdr2.msg_iovlen = 1;
                        ret = Syscall.recvmsg(so2, msghdr2, 0);
                    }
                    if (ret < 0)
                    {
                        UnixMarshal.ThrowExceptionForLastError();
                    }

                    var fds = new global::System.Collections.Generic.List <int> ();
                    for (offset = Syscall.CMSG_FIRSTHDR(msghdr2); offset != -1; offset = Syscall.CMSG_NXTHDR(msghdr2, offset))
                    {
                        var recvHdr        = Cmsghdr.ReadFromBuffer(msghdr2, offset);
                        var recvDataOffset = Syscall.CMSG_DATA(msghdr2, offset);
                        var bytes          = recvHdr.cmsg_len - (recvDataOffset - offset);
                        Assert.AreEqual(bytes % sizeof(int), 0);
                        var fdCount     = bytes / sizeof(int);
                        fixed(byte *ptr = msghdr2.msg_control)
                        for (int i = 0; i < fdCount; i++)
                        {
                            fds.Add(((int *)(ptr + recvDataOffset))[i]);
                        }
                    }
                    try {
                        Assert.IsTrue((msghdr2.msg_flags & MessageFlags.MSG_CTRUNC) == 0);                          // Control message has not been truncated

                        Assert.AreEqual(buffer1.Length, ret);
                        for (int i = 0; i < buffer1.Length; i++)
                        {
                            Assert.AreEqual(buffer1[i], buffer2[i]);
                        }

                        Assert.AreEqual(fds.Count, 2);

                        // Send message over the first received fd and receive it over inner_so2
                        var buffer3 = new byte[] { 16, 17 };
                        ret         = Syscall.send(fds[0], buffer3, (ulong)buffer3.Length, 0);
                        if (ret < 0)
                        {
                            UnixMarshal.ThrowExceptionForLastError();
                        }

                        var buffer4 = new byte[1024];
                        ret         = Syscall.recv(inner_so2, buffer4, (ulong)buffer4.Length, 0);
                        if (ret < 0)
                        {
                            UnixMarshal.ThrowExceptionForLastError();
                        }

                        Assert.AreEqual(buffer3.Length, ret);
                        for (int i = 0; i < buffer3.Length; i++)
                        {
                            Assert.AreEqual(buffer3[i], buffer4[i]);
                        }

                        // Send message over inner_so1 and receive it second received fd
                        var buffer5 = new byte[] { 10, 40, 0, 1 };
                        ret         = Syscall.send(inner_so1, buffer5, (ulong)buffer5.Length, 0);
                        if (ret < 0)
                        {
                            UnixMarshal.ThrowExceptionForLastError();
                        }

                        var buffer6 = new byte[1024];
                        ret         = Syscall.recv(fds[1], buffer6, (ulong)buffer6.Length, 0);
                        if (ret < 0)
                        {
                            UnixMarshal.ThrowExceptionForLastError();
                        }

                        Assert.AreEqual(buffer5.Length, ret);
                        for (int i = 0; i < buffer5.Length; i++)
                        {
                            Assert.AreEqual(buffer5[i], buffer6[i]);
                        }
                    } finally {
                        foreach (var fd in fds)
                        {
                            if (Syscall.close(fd) < 0)
                            {
                                UnixMarshal.ThrowExceptionForLastError();
                            }
                        }
                    }
                });
            });
        }
Пример #10
0
        [ExpectedException(typeof(ArgumentOutOfRangeException))]           // IPPROTO_UDP not supported
#endif
        public unsafe void SendMsgRecvMsgAddress()
        {
            WithSockets(UnixAddressFamily.AF_INET, UnixSocketType.SOCK_DGRAM, UnixSocketProtocol.IPPROTO_UDP, (so1, so2) => {
                // Bind UDP socket so1 to 127.0.0.1 with dynamic port
                var address = new SockaddrIn {
                    sin_family = UnixAddressFamily.AF_INET,
                    sin_port   = Syscall.htons(0),
                    sin_addr   = new InAddr(127, 0, 0, 1),
                };
                if (Syscall.bind(so1, address) < 0)
                {
                    UnixMarshal.ThrowExceptionForLastError();
                }

                // Get actual port number using getsockname()
                var actualAddress = new SockaddrIn();
                if (Syscall.getsockname(so1, actualAddress) < 0)
                {
                    UnixMarshal.ThrowExceptionForLastError();
                }
                Assert.AreEqual(actualAddress.sa_family, UnixAddressFamily.AF_INET);
                var port = Syscall.ntohs(actualAddress.sin_port);
                Assert.IsTrue(port != 0);


                var remoteAddress = new SockaddrIn {
                    sin_family = UnixAddressFamily.AF_INET,
                    sin_port   = Syscall.htons(port),
                    sin_addr   = new InAddr(127, 0, 0, 1),
                };

                // Send and receive a few bytes
                long ret;
                var buffer1             = new byte[] { 42, 43, 44 };
                fixed(byte *ptr_buffer1 = buffer1)
                {
                    var iovecs1 = new Iovec[] {
                        new Iovec {
                            iov_base = (IntPtr)ptr_buffer1,
                            iov_len  = (ulong)buffer1.Length,
                        },
                    };
                    var msghdr1 = new Msghdr {
                        msg_name   = remoteAddress,
                        msg_iov    = iovecs1,
                        msg_iovlen = 1,
                    };
                    ret = Syscall.sendmsg(so2, msghdr1, 0);
                    msghdr1.msg_name = remoteAddress.ToSockaddrStorage();
                    if (ret >= 0)
                    {
                        ret = Syscall.sendmsg(so2, msghdr1, 0);
                    }
                }
                if (ret < 0)
                {
                    UnixMarshal.ThrowExceptionForLastError();
                }

                var senderAddress        = new SockaddrIn();
                var senderAddressStorage = new SockaddrStorage();
                var buffer2             = new byte[1024];
                var buffer3             = new byte[1024];
                fixed(byte *ptr_buffer2 = buffer2, ptr_buffer3 = buffer3)
                {
                    var iovecs2 = new Iovec[] {
                        new Iovec {
                            iov_base = (IntPtr)ptr_buffer2,
                            iov_len  = (ulong)buffer2.Length,
                        },
                    };
                    var msghdr2 = new Msghdr {
                        msg_name   = senderAddress,
                        msg_iov    = iovecs2,
                        msg_iovlen = 1,
                    };
                    ret = Syscall.recvmsg(so1, msghdr2, 0);
                    msghdr2.msg_name    = senderAddressStorage;
                    iovecs2[0].iov_base = (IntPtr)ptr_buffer3;
                    if (ret >= 0)
                    {
                        ret = Syscall.recvmsg(so1, msghdr2, 0);
                    }
                }
                if (ret < 0)
                {
                    UnixMarshal.ThrowExceptionForLastError();
                }
                Assert.AreEqual(senderAddress.sa_family, UnixAddressFamily.AF_INET);
                Assert.AreEqual(senderAddress.sin_addr, new InAddr(127, 0, 0, 1));
                var senderAddress2 = SockaddrIn.FromSockaddrStorage(senderAddressStorage);
                Assert.AreEqual(senderAddress2.sa_family, UnixAddressFamily.AF_INET);
                Assert.AreEqual(senderAddress2.sin_addr, new InAddr(127, 0, 0, 1));

                Assert.AreEqual(buffer1.Length, ret);
                for (int i = 0; i < buffer1.Length; i++)
                {
                    Assert.AreEqual(buffer1[i], buffer2[i]);
                }
                for (int i = 0; i < buffer1.Length; i++)
                {
                    Assert.AreEqual(buffer1[i], buffer3[i]);
                }
            });
        }
Пример #11
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);
                }
            }
        }