#include <unistd.h>])
AC_CHECK_TYPES([suseconds_t], [AC_DEFINE(HAVE_SUSECONDS_T)], ,
[#include <sys/time.h>])
+ AC_CHECK_TYPES([struct cmsghdr], [AC_DEFINE(HAVE_STRUCT_CMSGHDR)], ,
+ [#include <sys/socket.h>])
AC_CHECK_TYPES([struct flock], [AC_DEFINE(HAVE_STRUCT_FLOCK)], ,
[#include <unistd.h>
#include <fcntl.h>])
return rval;
}
+ [DllImport (LIB, EntryPoint="Mono_Posix_FromCmsghdr")]
+ private static extern int FromCmsghdr (ref Cmsghdr source, IntPtr destination);
+
+ public static bool TryCopy (ref Cmsghdr source, IntPtr destination)
+ {
+ return FromCmsghdr (ref source, destination) == 0;
+ }
+
+ [DllImport (LIB, EntryPoint="Mono_Posix_ToCmsghdr")]
+ private static extern int ToCmsghdr (IntPtr source, out Cmsghdr destination);
+
+ public static bool TryCopy (IntPtr source, out Cmsghdr destination)
+ {
+ return ToCmsghdr (source, out destination) == 0;
+ }
+
[DllImport (LIB, EntryPoint="Mono_Posix_FromConfstrName")]
private static extern int FromConfstrName (ConfstrName value, out Int32 rval);
return rval;
}
+ [DllImport (LIB, EntryPoint="Mono_Posix_FromUnixSocketControlMessage")]
+ private static extern int FromUnixSocketControlMessage (UnixSocketControlMessage value, out Int32 rval);
+
+ public static bool TryFromUnixSocketControlMessage (UnixSocketControlMessage value, out Int32 rval)
+ {
+ return FromUnixSocketControlMessage (value, out rval) == 0;
+ }
+
+ public static Int32 FromUnixSocketControlMessage (UnixSocketControlMessage value)
+ {
+ Int32 rval;
+ if (FromUnixSocketControlMessage (value, out rval) == -1)
+ ThrowArgumentException (value);
+ return rval;
+ }
+
+ [DllImport (LIB, EntryPoint="Mono_Posix_ToUnixSocketControlMessage")]
+ private static extern int ToUnixSocketControlMessage (Int32 value, out UnixSocketControlMessage rval);
+
+ public static bool TryToUnixSocketControlMessage (Int32 value, out UnixSocketControlMessage rval)
+ {
+ return ToUnixSocketControlMessage (value, out rval) == 0;
+ }
+
+ public static UnixSocketControlMessage ToUnixSocketControlMessage (Int32 value)
+ {
+ UnixSocketControlMessage rval;
+ if (ToUnixSocketControlMessage (value, out rval) == -1)
+ ThrowArgumentException (value);
+ return rval;
+ }
+
[DllImport (LIB, EntryPoint="Mono_Posix_FromUnixSocketFlags")]
private static extern int FromUnixSocketFlags (UnixSocketFlags value, out Int32 rval);
MustBeWrapped = 0x8000,
}
+ [Map]
+ [CLSCompliant (false)]
+ public enum UnixSocketControlMessage : int {
+ SCM_RIGHTS = 0x01, /* Transfer file descriptors. */
+ SCM_CREDENTIALS = 0x02, /* Credentials passing. */
+ }
+
#endregion
#region Structures
}
}
+ [Map ("struct cmsghdr")]
+ [CLSCompliant (false)]
+ public struct Cmsghdr {
+ public long cmsg_len;
+ public UnixSocketProtocol cmsg_level;
+ public UnixSocketControlMessage cmsg_type;
+
+ [DllImport (Syscall.MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Cmsghdr_getsize")]
+ static extern int getsize ();
+ static readonly int size = getsize ();
+ public static int Size {
+ get {
+ return size;
+ }
+ }
+
+ // Read a struct cmsghdr from msgh.msg_control at offset cmsg and convert it to managed Cmsghdr structure
+ public static unsafe Cmsghdr ReadFromBuffer (Msghdr msgh, long cmsg)
+ {
+ if (msgh == null)
+ throw new ArgumentNullException ("msgh");
+ if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length)
+ throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh");
+ if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen)
+ throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg");
+
+ Cmsghdr hdr;
+ fixed (byte* ptr = msgh.msg_control)
+ if (!NativeConvert.TryCopy ((IntPtr) (ptr + cmsg), out hdr))
+ throw new ArgumentException ("Failed to convert from native struct", "buffer");
+ // SOL_SOCKET has the same value as IPPROTO_ICMP on linux.
+ // Make sure that cmsg_level is set to SOL_SOCKET in this case.
+ if (NativeConvert.FromUnixSocketProtocol (hdr.cmsg_level) == NativeConvert.FromUnixSocketProtocol (UnixSocketProtocol.SOL_SOCKET))
+ hdr.cmsg_level = UnixSocketProtocol.SOL_SOCKET;
+ return hdr;
+ }
+
+ // Convert the Cmsghdr to a native struct cmsghdr and write it to msgh.msg_control at offset cmsg
+ public unsafe void WriteToBuffer (Msghdr msgh, long cmsg)
+ {
+ if (msgh == null)
+ throw new ArgumentNullException ("msgh");
+ if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length)
+ throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh");
+ if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen)
+ throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg");
+
+ fixed (byte* ptr = msgh.msg_control)
+ if (!NativeConvert.TryCopy (ref this, (IntPtr) (ptr + cmsg)))
+ throw new ArgumentException ("Failed to convert to native struct", "buffer");
+ }
+ }
+
#endregion
#region Classes
}
}
+ [CLSCompliant (false)]
+ public sealed class Msghdr
+ {
+ public Sockaddr msg_name;
+ // msg_name_len is part of the Sockaddr structure
+ public Iovec[] msg_iov;
+ public int msg_iovlen;
+ public byte[] msg_control;
+ public long msg_controllen;
+ public MessageFlags msg_flags;
+ }
+
//
// Convention: Functions *not* part of the standard C library AND part of
// a POSIX and/or Unix standard (X/Open, SUS, XPG, etc.) go here.
#region <socket.h> Declarations
//
- // <socket.h>
+ // <socket.h> -- COMPLETE
//
// socket(2)
return sendto (socket, ptr, length, flags, address);
}
+ // structure for recvmsg() and sendmsg()
+ unsafe struct _Msghdr
+ {
+ public Iovec* msg_iov;
+ public int msg_iovlen;
+ public byte* msg_control;
+ public long msg_controllen;
+ public int msg_flags;
+
+ public _Msghdr (Msghdr message, Iovec* ptr_msg_iov, byte* ptr_msg_control)
+ {
+ if (message.msg_iovlen > message.msg_iov.Length || message.msg_iovlen < 0)
+ throw new ArgumentException ("message.msg_iovlen > message.msg_iov.Length || message.msg_iovlen < 0", "message");
+ msg_iov = ptr_msg_iov;
+ msg_iovlen = message.msg_iovlen;
+
+ if (message.msg_control == null && message.msg_controllen != 0)
+ throw new ArgumentException ("message.msg_control == null && message.msg_controllen != 0", "message");
+ if (message.msg_control != null && message.msg_controllen > message.msg_control.Length)
+ throw new ArgumentException ("message.msg_controllen > message.msg_control.Length", "message");
+ msg_control = ptr_msg_control;
+ msg_controllen = message.msg_controllen;
+
+ msg_flags = 0; // msg_flags is only passed out of the kernel
+ }
+
+ public void Update (Msghdr message)
+ {
+ message.msg_controllen = msg_controllen;
+ message.msg_flags = NativeConvert.ToMessageFlags (msg_flags);
+ }
+ }
+
+ // recvmsg(2)
+ // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_recvmsg")]
+ static extern unsafe long sys_recvmsg (int socket, ref _Msghdr message, _SockaddrHeader* msg_name, int flags);
+
+ public static unsafe long recvmsg (int socket, Msghdr message, MessageFlags flags)
+ {
+ var _flags = NativeConvert.FromMessageFlags (flags);
+ var address = message.msg_name;
+ fixed (byte* ptr_msg_control = message.msg_control)
+ fixed (Iovec* ptr_msg_iov = message.msg_iov) {
+ var _message = new _Msghdr (message, ptr_msg_iov, ptr_msg_control);
+ long r;
+ fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+ fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+ var dyn = new _SockaddrDynamic (address, data, useMaxLength: true);
+ r = sys_recvmsg (socket, ref _message, Sockaddr.GetNative (&dyn, addr), _flags);
+ dyn.Update (address);
+ }
+ _message.Update (message);
+ return r;
+ }
+ }
+
+ // sendmsg(2)
+ // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_sendmsg")]
+ static extern unsafe long sys_sendmsg (int socket, ref _Msghdr message, _SockaddrHeader* msg_name, int flags);
+
+ public static unsafe long sendmsg (int socket, Msghdr message, MessageFlags flags)
+ {
+ var _flags = NativeConvert.FromMessageFlags (flags);
+ var address = message.msg_name;
+ fixed (byte* ptr_msg_control = message.msg_control)
+ fixed (Iovec* ptr_msg_iov = message.msg_iov) {
+ var _message = new _Msghdr (message, ptr_msg_iov, ptr_msg_control);
+ fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+ fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+ var dyn = new _SockaddrDynamic (address, data, useMaxLength: false);
+ return sys_sendmsg (socket, ref _message, Sockaddr.GetNative (&dyn, addr), _flags);
+ }
+ }
+ }
+
+ // cmsg(3)
+ // struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);
+ // struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);
+ // size_t CMSG_ALIGN(size_t length);
+ // size_t CMSG_SPACE(size_t length);
+ // size_t CMSG_LEN(size_t length);
+ // unsigned char *CMSG_DATA(struct cmsghdr *cmsg);
+
+ // Wrapper methods use long offsets into msg_control instead of a
+ // struct cmsghdr *cmsg pointer because pointers into a byte[] aren't
+ // stable when the array is not pinned.
+ // NULL is mapped to -1.
+
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_CMSG_FIRSTHDR")]
+ static extern unsafe long CMSG_FIRSTHDR (byte* msg_control, long msg_controllen);
+
+ public static unsafe long CMSG_FIRSTHDR (Msghdr msgh)
+ {
+ if (msgh.msg_control == null && msgh.msg_controllen != 0)
+ throw new ArgumentException ("msgh.msg_control == null && msgh.msg_controllen != 0", "msgh");
+ if (msgh.msg_control != null && msgh.msg_controllen > msgh.msg_control.Length)
+ throw new ArgumentException ("msgh.msg_controllen > msgh.msg_control.Length", "msgh");
+
+ fixed (byte* ptr = msgh.msg_control)
+ return CMSG_FIRSTHDR (ptr, msgh.msg_controllen);
+ }
+
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_CMSG_NXTHDR")]
+ static extern unsafe long CMSG_NXTHDR (byte* msg_control, long msg_controllen, long cmsg);
+
+ public static unsafe long CMSG_NXTHDR (Msghdr msgh, long cmsg)
+ {
+ if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length)
+ throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh");
+ if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen)
+ throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg");
+
+ fixed (byte* ptr = msgh.msg_control)
+ return CMSG_NXTHDR (ptr, msgh.msg_controllen, cmsg);
+ }
+
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_CMSG_DATA")]
+ static extern unsafe long CMSG_DATA (byte* msg_control, long msg_controllen, long cmsg);
+
+ public static unsafe long CMSG_DATA (Msghdr msgh, long cmsg)
+ {
+ if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length)
+ throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh");
+ if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen)
+ throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg");
+
+ fixed (byte* ptr = msgh.msg_control)
+ return CMSG_DATA (ptr, msgh.msg_controllen, cmsg);
+ }
+
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_CMSG_ALIGN")]
+ public static extern ulong CMSG_ALIGN (ulong length);
+
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_CMSG_SPACE")]
+ public static extern ulong CMSG_SPACE (ulong length);
+
+ [DllImport (MPH, SetLastError=true,
+ EntryPoint="Mono_Posix_Syscall_CMSG_LEN")]
+ public static extern ulong CMSG_LEN (ulong length);
+
#endregion
}
Assert.AreEqual (buffer1[i], buffer2[i]);
});
}
+
+ [Test]
+ 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]);
+ });
+ }
+
+ [Test]
+ 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]);
+ });
+ }
+
+ [Test]
+ public unsafe void ControlMsg ()
+ {
+ // 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) => {
+ // Create two SCM_RIGHTS control messages
+ var 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,
+ };
+ var msghdr1 = new Msghdr {
+ msg_control = cmsg,
+ msg_controllen = cmsg.Length,
+ };
+ long 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;
+ }
+
+ 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 ();
+
+ 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 ();
+ }
+ });
+ });
+ }
}
}
sys-statvfs.c \
sys-time.c \
sys-uio.c \
+ sys-uio.h \
sys-utsname.c \
sys-wait.c \
sys-xattr.c \
return 0;
}
+#ifdef HAVE_STRUCT_CMSGHDR
+int
+Mono_Posix_FromCmsghdr (struct Mono_Posix_Cmsghdr *from, struct cmsghdr *to)
+{
+ _cnm_return_val_if_overflow (gint64, from->cmsg_len, -1);
+
+ memset (to, 0, sizeof(*to));
+
+ to->cmsg_len = from->cmsg_len;
+ if (Mono_Posix_FromUnixSocketProtocol (from->cmsg_level, &to->cmsg_level) != 0) {
+ return -1;
+ }
+ if (Mono_Posix_FromUnixSocketControlMessage (from->cmsg_type, &to->cmsg_type) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* ndef HAVE_STRUCT_CMSGHDR */
+
+
+#ifdef HAVE_STRUCT_CMSGHDR
+int
+Mono_Posix_ToCmsghdr (struct cmsghdr *from, struct Mono_Posix_Cmsghdr *to)
+{
+ _cnm_return_val_if_overflow (gint64, from->cmsg_len, -1);
+
+ memset (to, 0, sizeof(*to));
+
+ to->cmsg_len = from->cmsg_len;
+ if (Mono_Posix_ToUnixSocketProtocol (from->cmsg_level, &to->cmsg_level) != 0) {
+ return -1;
+ }
+ if (Mono_Posix_ToUnixSocketControlMessage (from->cmsg_type, &to->cmsg_type) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* ndef HAVE_STRUCT_CMSGHDR */
+
+
int Mono_Posix_FromConfstrName (int x, int *r)
{
*r = 0;
errno = EINVAL; return -1;
}
+int Mono_Posix_FromUnixSocketControlMessage (int x, int *r)
+{
+ *r = 0;
+ if (x == Mono_Posix_UnixSocketControlMessage_SCM_CREDENTIALS)
+#ifdef SCM_CREDENTIALS
+ {*r = SCM_CREDENTIALS; return 0;}
+#else /* def SCM_CREDENTIALS */
+ {errno = EINVAL; return -1;}
+#endif /* ndef SCM_CREDENTIALS */
+ if (x == Mono_Posix_UnixSocketControlMessage_SCM_RIGHTS)
+#ifdef SCM_RIGHTS
+ {*r = SCM_RIGHTS; return 0;}
+#else /* def SCM_RIGHTS */
+ {errno = EINVAL; return -1;}
+#endif /* ndef SCM_RIGHTS */
+ if (x == 0)
+ return 0;
+ errno = EINVAL; return -1;
+}
+
+int Mono_Posix_ToUnixSocketControlMessage (int x, int *r)
+{
+ *r = 0;
+ if (x == 0)
+ return 0;
+#ifdef SCM_CREDENTIALS
+ if (x == SCM_CREDENTIALS)
+ {*r = Mono_Posix_UnixSocketControlMessage_SCM_CREDENTIALS; return 0;}
+#endif /* ndef SCM_CREDENTIALS */
+#ifdef SCM_RIGHTS
+ if (x == SCM_RIGHTS)
+ {*r = Mono_Posix_UnixSocketControlMessage_SCM_RIGHTS; return 0;}
+#endif /* ndef SCM_RIGHTS */
+ errno = EINVAL; return -1;
+}
+
int Mono_Posix_FromUnixSocketFlags (int x, int *r)
{
*r = 0;
int Mono_Posix_FromUnixAddressFamily (int x, int *r);
int Mono_Posix_ToUnixAddressFamily (int x, int *r);
+enum Mono_Posix_UnixSocketControlMessage {
+ Mono_Posix_UnixSocketControlMessage_SCM_CREDENTIALS = 0x00000002,
+ #define Mono_Posix_UnixSocketControlMessage_SCM_CREDENTIALS Mono_Posix_UnixSocketControlMessage_SCM_CREDENTIALS
+ Mono_Posix_UnixSocketControlMessage_SCM_RIGHTS = 0x00000001,
+ #define Mono_Posix_UnixSocketControlMessage_SCM_RIGHTS Mono_Posix_UnixSocketControlMessage_SCM_RIGHTS
+};
+int Mono_Posix_FromUnixSocketControlMessage (int x, int *r);
+int Mono_Posix_ToUnixSocketControlMessage (int x, int *r);
+
enum Mono_Posix_UnixSocketFlags {
Mono_Posix_UnixSocketFlags_SOCK_CLOEXEC = 0x00080000,
#define Mono_Posix_UnixSocketFlags_SOCK_CLOEXEC Mono_Posix_UnixSocketFlags_SOCK_CLOEXEC
* Managed Structure Declarations
*/
+struct Mono_Posix_Cmsghdr;
struct Mono_Posix_Flock;
struct Mono_Posix_In6Addr;
struct Mono_Posix_InAddr;
struct Mono_Posix_Syscall__Dirent;
struct Mono_Posix_Syscall__Fstab;
struct Mono_Posix_Syscall__Group;
+struct Mono_Posix_Syscall__Msghdr;
struct Mono_Posix_Syscall__Passwd;
struct Mono_Posix_Syscall__Utsname;
struct Mono_Posix_Timespec;
* Inferred Structure Declarations
*/
+struct cmsghdr;
struct flock;
struct iovec;
struct linger;
* Structures
*/
+struct Mono_Posix_Cmsghdr {
+ gint64 cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+};
+
+int
+Mono_Posix_FromCmsghdr (struct Mono_Posix_Cmsghdr* from, struct cmsghdr *to);
+int
+Mono_Posix_ToCmsghdr (struct cmsghdr *from, struct Mono_Posix_Cmsghdr* to);
+
+
struct Mono_Posix_Flock {
short l_type;
short l_whence;
void* _gr_buf_;
};
+struct Mono_Posix_Syscall__Msghdr {
+ struct Mono_Posix_Iovec* msg_iov;
+ int msg_iovlen;
+ unsigned char* msg_control;
+ gint64 msg_controllen;
+ int msg_flags;
+};
+
struct Mono_Posix_Syscall__Passwd {
void* pw_name;
void* pw_passwd;
int map_Mono_Posix_FileMode (int mode);
int map_Mono_Posix_OpenFlags (int flags);
int map_Mono_Posix_WaitOptions (int wait_options);
+int Mono_Posix_Cmsghdr_getsize (void);
int Mono_Posix_FromIn6Addr (struct Mono_Posix_In6Addr* source, void* destination);
int Mono_Posix_FromInAddr (struct Mono_Posix_InAddr* source, void* destination);
int Mono_Posix_FromRealTimeSignum (int offset, int* rval);
void* Mono_Posix_Stdlib_CreateFilePosition (void);
int Mono_Posix_Stdlib_DumpFilePosition (char* buf, void* handle, int len);
int Mono_Posix_Stdlib_EOF (void);
-const char* Mono_Unix_VersionString (void);
int Mono_Posix_Stdlib_EXIT_FAILURE (void);
int Mono_Posix_Stdlib_EXIT_SUCCESS (void);
int Mono_Posix_Stdlib_fgetpos (void* stream, void* pos);
int Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* address, int flags);
int Mono_Posix_Syscall_bind (int socket, struct Mono_Posix__SockaddrHeader* address);
int Mono_Posix_Syscall_closelog (void);
+guint64 Mono_Posix_Syscall_CMSG_ALIGN (guint64 length);
+gint64 Mono_Posix_Syscall_CMSG_DATA (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg);
+gint64 Mono_Posix_Syscall_CMSG_FIRSTHDR (unsigned char* msg_control, gint64 msg_controllen);
+guint64 Mono_Posix_Syscall_CMSG_LEN (guint64 length);
+gint64 Mono_Posix_Syscall_CMSG_NXTHDR (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg);
+guint64 Mono_Posix_Syscall_CMSG_SPACE (guint64 length);
guint64 Mono_Posix_Syscall_confstr (int name, char* buf, guint64 len);
int Mono_Posix_Syscall_connect (int socket, struct Mono_Posix__SockaddrHeader* address);
int Mono_Posix_Syscall_creat (const char* pathname, unsigned int mode);
gint64 Mono_Posix_Syscall_readv (int fd, struct Mono_Posix_Iovec* iov, int iovcnt);
gint64 Mono_Posix_Syscall_recv (int socket, void* buffer, guint64 length, int flags);
gint64 Mono_Posix_Syscall_recvfrom (int socket, void* buffer, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address);
+gint64 Mono_Posix_Syscall_recvmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* msg_name, int flags);
int Mono_Posix_Syscall_remap_file_pages (void* start, guint64 size, int prot, gint64 pgoff, int flags);
int Mono_Posix_Syscall_removexattr (const char* path, const char* name);
int Mono_Posix_Syscall_rewinddir (void* dir);
int Mono_Posix_Syscall_seekdir (void* dir, gint64 offset);
gint64 Mono_Posix_Syscall_send (int socket, void* message, guint64 length, int flags);
gint64 Mono_Posix_Syscall_sendfile (int out_fd, int in_fd, gint64* offset, guint64 count);
+gint64 Mono_Posix_Syscall_sendmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* msg_name, int flags);
gint64 Mono_Posix_Syscall_sendto (int socket, void* message, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address);
int Mono_Posix_Syscall_setdomainname (const char* name, guint64 len);
int Mono_Posix_Syscall_setfsent (void);
void* Mono_Unix_UnixSignal_install (int signum);
int Mono_Unix_UnixSignal_uninstall (void* info);
int Mono_Unix_UnixSignal_WaitAny (void** infos, int count, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down);
+void* Mono_Unix_VersionString (void);
int wexitstatus (int status);
int wifexited (int status);
int wifsignaled (int status);
G_BEGIN_DECLS
// See Stdlib.cs
-const char *
+void*
Mono_Unix_VersionString ()
{
return "MonoProject-2015-12-1";
#include "map.h"
#include "mph.h"
+#include "sys-uio.h"
G_BEGIN_DECLS
return sizeof (sun.sun_path);
}
+int
+Mono_Posix_Cmsghdr_getsize (void)
+{
+ return sizeof (struct cmsghdr);
+}
+
int
Mono_Posix_FromInAddr (struct Mono_Posix_InAddr* source, void* destination)
{
return r;
}
+#ifdef HAVE_ACCEPT4
int
Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* address, int flags)
{
-#ifdef HAVE_ACCEPT4
int r;
ALLOC_SOCKADDR
free (addr);
return r;
-#else
- errno = EINVAL;
- return -1;
-#endif
}
+#endif
int
Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address)
return r;
}
+gint64
+Mono_Posix_Syscall_recvmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
+{
+ struct msghdr hdr;
+ int r;
+
+ ALLOC_SOCKADDR
+
+ memset (&hdr, 0, sizeof (struct msghdr));
+
+ hdr.msg_name = addr;
+ hdr.msg_namelen = addrlen;
+ hdr.msg_iovlen = message->msg_iovlen;
+ hdr.msg_control = message->msg_control;
+ hdr.msg_controllen = message->msg_controllen;
+
+ hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
+
+ r = recvmsg (socket, &hdr, flags);
+
+ if (r != -1 && Mono_Posix_ToSockaddr (addr, hdr.msg_namelen, address) != 0)
+ r = -1;
+
+ free (hdr.msg_iov);
+ if (need_free)
+ free (addr);
+
+ message->msg_controllen = hdr.msg_controllen;
+ message->msg_flags = hdr.msg_flags;
+
+ return r;
+}
+
+gint64
+Mono_Posix_Syscall_sendmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
+{
+ struct msghdr hdr;
+ int r;
+
+ ALLOC_SOCKADDR
+ if (Mono_Posix_FromSockaddr (address, addr) != 0) {
+ if (need_free)
+ free (addr);
+ return -1;
+ }
+
+ memset (&hdr, 0, sizeof (struct msghdr));
+
+ hdr.msg_name = addr;
+ hdr.msg_namelen = addrlen;
+ hdr.msg_iovlen = message->msg_iovlen;
+ hdr.msg_control = message->msg_control;
+ hdr.msg_controllen = message->msg_controllen;
+
+ hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
+
+ r = sendmsg (socket, &hdr, flags);
+
+ free (hdr.msg_iov);
+ if (need_free)
+ free (addr);
+
+ return r;
+}
+
+static inline void make_msghdr (struct msghdr* hdr, unsigned char* msg_control, gint64 msg_controllen)
+{
+ memset (hdr, 0, sizeof (struct msghdr));
+ hdr->msg_control = msg_control;
+ hdr->msg_controllen = msg_controllen;
+}
+static inline struct cmsghdr* from_offset (unsigned char* msg_control, gint64 offset)
+{
+ if (offset == -1)
+ return NULL;
+ return (struct cmsghdr*) (msg_control + offset);
+}
+static inline gint64 to_offset (unsigned char* msg_control, void* hdr)
+{
+ if (!hdr)
+ return -1;
+ return ((unsigned char*) hdr) - msg_control;
+}
+
+#ifdef CMSG_FIRSTHDR
+gint64
+Mono_Posix_Syscall_CMSG_FIRSTHDR (unsigned char* msg_control, gint64 msg_controllen)
+{
+ struct msghdr hdr;
+
+ make_msghdr (&hdr, msg_control, msg_controllen);
+ return to_offset (msg_control, CMSG_FIRSTHDR (&hdr));
+}
+#endif
+
+#ifdef CMSG_NXTHDR
+gint64
+Mono_Posix_Syscall_CMSG_NXTHDR (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
+{
+ struct msghdr hdr;
+
+ make_msghdr (&hdr, msg_control, msg_controllen);
+ return to_offset (msg_control, CMSG_NXTHDR (&hdr, from_offset (msg_control, cmsg)));
+}
+#endif
+
+#ifdef CMSG_DATA
+gint64
+Mono_Posix_Syscall_CMSG_DATA (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
+{
+ return to_offset (msg_control, CMSG_DATA (from_offset (msg_control, cmsg)));
+}
+#endif
+
+#ifdef CMSG_ALIGN
+guint64
+Mono_Posix_Syscall_CMSG_ALIGN (guint64 length)
+{
+ return CMSG_ALIGN (length);
+}
+#endif
+
+#ifdef CMSG_SPACE
+guint64
+Mono_Posix_Syscall_CMSG_SPACE (guint64 length)
+{
+ return CMSG_SPACE (length);
+}
+#endif
+
+#ifdef CMSG_LEN
+guint64
+Mono_Posix_Syscall_CMSG_LEN (guint64 length)
+{
+ return CMSG_LEN (length);
+}
+#endif
+
+/*
+ * vim: noexpandtab
+ */
+
// vim: noexpandtab
// Local Variables:
// tab-width: 4
#define _GNU_SOURCE
#endif /* ndef _GNU_SOURCE */
+#include "sys-uio.h"
+
#include <sys/uio.h>
#include "map.h"
G_BEGIN_DECLS
-static struct iovec*
-from_iovec (struct Mono_Posix_Iovec *iov, gint32 iovcnt)
+struct iovec*
+_mph_from_iovec_array (struct Mono_Posix_Iovec *iov, gint32 iovcnt)
{
struct iovec* v;
gint32 i;
struct iovec* v;
gint64 res;
- v = from_iovec (iov, iovcnt);
+ v = _mph_from_iovec_array (iov, iovcnt);
if (!v) {
return -1;
}
struct iovec* v;
gint64 res;
- v = from_iovec (iov, iovcnt);
+ v = _mph_from_iovec_array (iov, iovcnt);
if (!v) {
return -1;
}
mph_return_if_off_t_overflow (off);
- v = from_iovec (iov, iovcnt);
+ v = _mph_from_iovec_array (iov, iovcnt);
if (!v) {
return -1;
}
mph_return_if_off_t_overflow (off);
- v = from_iovec (iov, iovcnt);
+ v = _mph_from_iovec_array (iov, iovcnt);
if (!v) {
return -1;
}
--- /dev/null
+#ifndef SYS_UIO_H
+#define SYS_UIO_H
+
+#include <glib.h>
+
+#include <sys/uio.h>
+
+#include "map.h"
+#include "mph.h"
+
+G_BEGIN_DECLS
+
+MPH_INTERNAL struct iovec*
+_mph_from_iovec_array (struct Mono_Posix_Iovec *iov, gint32 iovcnt);
+
+G_END_DECLS
+
+#endif /* SYS_UIO_H */