[Mono.Posix] Add support for sending and receiving socket control messages
authorSteffen Kieß <s-kiess@web.de>
Tue, 19 Jan 2016 19:43:07 +0000 (20:43 +0100)
committerSteffen Kieß <s-kiess@web.de>
Tue, 19 Jan 2016 19:43:07 +0000 (20:43 +0100)
Add wrappers for struct cmsghdr, the macros for manipulating control
messages (CMSG_*) and recvmsg() and sendmsg().

configure.ac
mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs
mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs
mcs/class/Mono.Posix/Test/Mono.Unix.Native/SocketTest.cs
support/Makefile.am
support/map.c
support/map.h
support/stdlib.c
support/sys-socket.c
support/sys-uio.c
support/sys-uio.h [new file with mode: 0644]

index 82421f3593ade89387572920be92d4c9d78b9fce..4131664f25fcb764321b860256a05c7a242b194c 100644 (file)
@@ -2090,6 +2090,8 @@ if test x$host_win32 = xno; then
                 #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>])
index 436235334a157beb47b7831e0091fcc5b4e9eadf..d980bbf22c600104e0ec7b2ab1f859cc1f837912 100644 (file)
@@ -86,6 +86,22 @@ namespace Mono.Unix.Native {
                        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);
 
@@ -1190,6 +1206,38 @@ namespace Mono.Unix.Native {
                        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);
 
index 4ab7ed53ad6618270bc52ce8e03ee756e7935781..cbeb54b0ec2778f87a457f5494c2f349d5ddb223 100644 (file)
@@ -924,6 +924,13 @@ namespace Mono.Unix.Native {
                MustBeWrapped = 0x8000,
        }
 
+       [Map]
+       [CLSCompliant (false)]
+       public enum UnixSocketControlMessage : int {
+               SCM_RIGHTS      = 0x01,  /* Transfer file descriptors. */
+               SCM_CREDENTIALS = 0x02,  /* Credentials passing. */
+       }
+
        #endregion
 
        #region Structures
@@ -1576,6 +1583,60 @@ namespace Mono.Unix.Native {
                }
        }
 
+       [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
@@ -2386,6 +2447,18 @@ namespace Mono.Unix.Native {
                }
        }
 
+       [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.
@@ -5250,7 +5323,7 @@ namespace Mono.Unix.Native {
 
                #region <socket.h> Declarations
                //
-               // <socket.h>
+               // <socket.h> -- COMPLETE
                //
 
                // socket(2)
@@ -5642,6 +5715,155 @@ namespace Mono.Unix.Native {
                                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
        }
 
index dd5ed9bf40b775fa7721c5c439716c9a5b847f88..c16884dca0c9d1a573b462f7b017e8a36727c1b6 100644 (file)
@@ -596,6 +596,292 @@ namespace MonoTests.Mono.Unix.Native
                                        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 ();
+                                       }
+                               });
+                       });
+               }
        }
 }
 
index be3864cc9dab1facb674ed486098cf0efcf8c846..969ff60e4db002c8b5abe4f7360b1b48a6add11b 100644 (file)
@@ -44,6 +44,7 @@ MPH_UNIX_SOURCE =                             \
        sys-statvfs.c                           \
        sys-time.c                              \
        sys-uio.c                               \
+       sys-uio.h                               \
        sys-utsname.c   \
        sys-wait.c                              \
        sys-xattr.c                             \
index 6201c260c93369f1e37c4ceb340fe7c693b9a055..136f2b71878105b87fdcb5ccb5faa0f1cc943646 100644 (file)
@@ -367,6 +367,48 @@ int Mono_Posix_ToAtFlags (int x, int *r)
        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;
@@ -8247,6 +8289,42 @@ int Mono_Posix_ToUnixAddressFamily (int x, int *r)
        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;
index e95b4f9c4d8bc5a071be87db28a02f673ac28689..ccd221b106a219d161e744e9e6f42828089f7130 100644 (file)
@@ -1612,6 +1612,15 @@ enum Mono_Posix_UnixAddressFamily {
 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
@@ -1819,6 +1828,7 @@ int Mono_Posix_ToXattrFlags (int x, int *r);
  * Managed Structure Declarations
  */
 
+struct Mono_Posix_Cmsghdr;
 struct Mono_Posix_Flock;
 struct Mono_Posix_In6Addr;
 struct Mono_Posix_InAddr;
@@ -1832,6 +1842,7 @@ struct Mono_Posix_Statvfs;
 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;
@@ -1846,6 +1857,7 @@ struct Mono_Unix_UnixSignal_SignalInfo;
  * Inferred Structure Declarations
  */
 
+struct cmsghdr;
 struct flock;
 struct iovec;
 struct linger;
@@ -1867,6 +1879,18 @@ typedef int (*Mono_Posix_RuntimeIsShuttingDown) (void);
  * 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;
@@ -2014,6 +2038,14 @@ struct Mono_Posix_Syscall__Group {
        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;
@@ -2114,6 +2146,7 @@ int map_Mono_Posix_AccessMode (int mode);
 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);
@@ -2131,7 +2164,6 @@ int Mono_Posix_Stdlib_clearerr (void* stream);
 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);
@@ -2168,6 +2200,12 @@ int Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* ad
 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);
@@ -2264,12 +2302,14 @@ gint64 Mono_Posix_Syscall_readlinkat (int dirfd, const char* pathname, unsigned
 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);
@@ -2317,6 +2357,7 @@ int Mono_Posix_ToStatvfs (void* source, struct Mono_Posix_Statvfs* destination);
 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);
index 523ae92482899dca3582cb5103d2e085506530d6..0c4358a51402d3d7b2b577db88eef64497857af2 100644 (file)
@@ -15,7 +15,7 @@
 G_BEGIN_DECLS
 
 // See Stdlib.cs
-const char *
+void*
 Mono_Unix_VersionString ()
 {
        return "MonoProject-2015-12-1";
index 36da7d51661d14cff31ceec3ce37a2c08dad9657..9d43087ecdd0a7dc85b75758c493e2f5f66cefb2 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "map.h"
 #include "mph.h"
+#include "sys-uio.h"
 
 G_BEGIN_DECLS
 
@@ -33,6 +34,12 @@ Mono_Posix_SockaddrUn_get_sizeof_sun_path (void)
        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)
 {
@@ -394,10 +401,10 @@ Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* addres
        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
@@ -413,11 +420,8 @@ Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* addre
                free (addr);
 
        return r;
-#else
-       errno = EINVAL;
-       return -1;
-#endif
 }
+#endif
 
 int
 Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address)
@@ -513,6 +517,148 @@ Mono_Posix_Syscall_sendto (int socket, void* message, guint64 length, int flags,
        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
index f6b80e0d740ad70b0c2d6b937ed634fb3835718d..53e162f9fdada02a7a334006b116f749a1475ac6 100644 (file)
@@ -11,6 +11,8 @@
 #define _GNU_SOURCE
 #endif /* ndef _GNU_SOURCE */
 
+#include "sys-uio.h"
+
 #include <sys/uio.h>
 
 #include "map.h"
@@ -18,8 +20,8 @@
 
 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;
@@ -51,7 +53,7 @@ Mono_Posix_Syscall_readv (int dirfd, struct Mono_Posix_Iovec *iov, gint32 iovcnt
        struct iovec* v;
        gint64 res;
 
-       v = from_iovec (iov, iovcnt);
+       v = _mph_from_iovec_array (iov, iovcnt);
        if (!v) {
                return -1;
        }
@@ -69,7 +71,7 @@ Mono_Posix_Syscall_writev (int dirfd, struct Mono_Posix_Iovec *iov, gint32 iovcn
        struct iovec* v;
        gint64 res;
 
-       v = from_iovec (iov, iovcnt);
+       v = _mph_from_iovec_array (iov, iovcnt);
        if (!v) {
                return -1;
        }
@@ -89,7 +91,7 @@ Mono_Posix_Syscall_preadv (int dirfd, struct Mono_Posix_Iovec *iov, gint32 iovcn
 
        mph_return_if_off_t_overflow (off);
 
-       v = from_iovec (iov, iovcnt);
+       v = _mph_from_iovec_array (iov, iovcnt);
        if (!v) {
                return -1;
        }
@@ -109,7 +111,7 @@ Mono_Posix_Syscall_pwritev (int dirfd, struct Mono_Posix_Iovec *iov, gint32 iovc
 
        mph_return_if_off_t_overflow (off);
 
-       v = from_iovec (iov, iovcnt);
+       v = _mph_from_iovec_array (iov, iovcnt);
        if (!v) {
                return -1;
        }
diff --git a/support/sys-uio.h b/support/sys-uio.h
new file mode 100644 (file)
index 0000000..b5fb7c2
--- /dev/null
@@ -0,0 +1,18 @@
+#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 */