[Mono.Posix] Add wrappers for struct sockaddr_*
authorSteffen Kieß <s-kiess@web.de>
Mon, 18 Jan 2016 09:04:09 +0000 (10:04 +0100)
committerSteffen Kieß <s-kiess@web.de>
Mon, 18 Jan 2016 09:04:09 +0000 (10:04 +0100)
Add wrappers for the sockaddr_* structures and add the syscalls using these
structures (bind(), accept(), ...).

configure.ac
mcs/class/Mono.Posix/Makefile
mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs
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/sys-socket.c

index e26a851de63b8bdd8fd3f4c0a498b33ed824c84a..11dba9d461bd3538dd01532a969f1a74e5f63319 100644 (file)
@@ -2092,6 +2092,16 @@ if test x$host_win32 = xno; then
                [#include <sys/socket.h>])
        AC_CHECK_TYPES([struct pollfd], [AC_DEFINE(HAVE_STRUCT_POLLFD)], ,
                [#include <sys/poll.h>])
+       AC_CHECK_TYPES([struct sockaddr], [AC_DEFINE(HAVE_STRUCT_SOCKADDR)], ,
+               [#include <sys/socket.h>])
+       AC_CHECK_TYPES([struct sockaddr_storage], [AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)], ,
+               [#include <sys/socket.h>])
+       AC_CHECK_TYPES([struct sockaddr_in], [AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN)], ,
+               [#include <netinet/in.h>])
+       AC_CHECK_TYPES([struct sockaddr_in6], [AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6)], ,
+               [#include <netinet/in.h>])
+       AC_CHECK_TYPES([struct sockaddr_un], [AC_DEFINE(HAVE_STRUCT_SOCKADDR_UN)], ,
+               [#include <sys/un.h>])
        AC_CHECK_TYPES([struct stat], [AC_DEFINE(HAVE_STRUCT_STAT)], ,
                [#include <sys/types.h>
                 #include <sys/stat.h>
index fa0f5180187f518997f214be37011d62013b3fd5..9cde3498e4d17dde9a74721a7ad9a25052da0ec4 100644 (file)
@@ -7,7 +7,7 @@ LIBRARY = Mono.Posix.dll
 # members, generating volumes of output.
 LIB_REFS = System
 LIB_MCS_FLAGS = /unsafe /r:$(corlib) /nowarn:0618,612
-TEST_MCS_FLAGS = /r:Mono.Posix.dll /r:System.dll /nowarn:0219,0618
+TEST_MCS_FLAGS = /unsafe /r:Mono.Posix.dll /r:System.dll /nowarn:0219,0618
 
 LIBRARY_COMPILE = $(BOOT_COMPILE)
 
index 4e2613b127991263f8ba2d31fede7f7da2a99f1f..57c03140112b75746de381257b13e4b763886f5c 100644 (file)
@@ -359,7 +359,117 @@ namespace Mono.Unix.Native {
                {
                        return ToStatvfs (source, out destination) == 0;
                }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_FromInAddr")]
+               private static extern int FromInAddr (ref InAddr source, IntPtr destination);
+
+               public static bool TryCopy (ref InAddr source, IntPtr destination)
+               {
+                       return FromInAddr (ref source, destination) == 0;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_ToInAddr")]
+               private static extern int ToInAddr (IntPtr source, out InAddr destination);
+
+               public static bool TryCopy (IntPtr source, out InAddr destination)
+               {
+                       return ToInAddr (source, out destination) == 0;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_FromIn6Addr")]
+               private static extern int FromIn6Addr (ref In6Addr source, IntPtr destination);
+
+               public static bool TryCopy (ref In6Addr source, IntPtr destination)
+               {
+                       return FromIn6Addr (ref source, destination) == 0;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_ToIn6Addr")]
+               private static extern int ToIn6Addr (IntPtr source, out In6Addr destination);
+
+               public static bool TryCopy (IntPtr source, out In6Addr destination)
+               {
+                       return ToIn6Addr (source, out destination) == 0;
+               }
+
+               public static InAddr ToInAddr (System.Net.IPAddress address)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+                       if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
+                               throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork");
+                       return new InAddr (address.GetAddressBytes ());
+               }
+
+               public static System.Net.IPAddress ToIPAddress (InAddr address)
+               {
+                       var bytes = new byte[4];
+                       address.CopyTo (bytes, 0);
+                       return new System.Net.IPAddress (bytes);
+               }
+
+               public static In6Addr ToIn6Addr (System.Net.IPAddress address)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+                       if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
+                               throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6");
+                       return new In6Addr (address.GetAddressBytes ());
+               }
+
+               public static System.Net.IPAddress ToIPAddress (In6Addr address)
+               {
+                       var bytes = new byte[16];
+                       address.CopyTo (bytes, 0);
+                       return new System.Net.IPAddress (bytes);
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddr")]
+               private static extern unsafe int FromSockaddr (_SockaddrHeader* source, IntPtr destination);
+
+               public static unsafe bool TryCopy (Sockaddr source, IntPtr destination)
+               {
+                       if (source == null)
+                               throw new ArgumentNullException ("source");
+                       byte[] array = Sockaddr.GetDynamicData (source);
+                       // SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
+                       if (source.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
+                               Marshal.Copy (array, 0, destination, (int) source.GetDynamicLength ());
+                               return true;
+                       }
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (source).type)
+                       fixed (byte* data = array) {
+                               var dyn = new _SockaddrDynamic (source, data, useMaxLength: false);
+                               return FromSockaddr (Sockaddr.GetNative (&dyn, addr), destination) == 0;
+                       }
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddr")]
+               private static extern unsafe int ToSockaddr (IntPtr source, long size, _SockaddrHeader* destination);
+
+               public static unsafe bool TryCopy (IntPtr source, long size, Sockaddr destination)
+               {
+                       if (destination == null)
+                               throw new ArgumentNullException ("destination");
+                       byte[] array = Sockaddr.GetDynamicData (destination);
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (destination).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (destination)) {
+                               var dyn = new _SockaddrDynamic (destination, data, useMaxLength: true);
+                               var r = ToSockaddr (source, size, Sockaddr.GetNative (&dyn, addr));
+                               dyn.Update (destination);
+                               // SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
+                               if (r == 0 && destination.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
+                                       Marshal.Copy (source, array, 0, (int) destination.GetDynamicLength ());
+                               }
+                               return r == 0;
+                       }
+               }
        }
 }
 
 // vim: noexpandtab
+// Local Variables: 
+// tab-width: 4
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// End: 
index 2ac13c6677edd26437a6fc806df7cf3e12b6d027..436235334a157beb47b7831e0091fcc5b4e9eadf 100644 (file)
@@ -918,6 +918,70 @@ namespace Mono.Unix.Native {
                        return rval;
                }
 
+               [DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddrIn")]
+               private static extern int FromSockaddrIn (SockaddrIn source, IntPtr destination);
+
+               public static bool TryCopy (SockaddrIn source, IntPtr destination)
+               {
+                       return FromSockaddrIn (source, destination) == 0;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddrIn")]
+               private static extern int ToSockaddrIn (IntPtr source, SockaddrIn destination);
+
+               public static bool TryCopy (IntPtr source, SockaddrIn destination)
+               {
+                       return ToSockaddrIn (source, destination) == 0;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddrIn6")]
+               private static extern int FromSockaddrIn6 (SockaddrIn6 source, IntPtr destination);
+
+               public static bool TryCopy (SockaddrIn6 source, IntPtr destination)
+               {
+                       return FromSockaddrIn6 (source, destination) == 0;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddrIn6")]
+               private static extern int ToSockaddrIn6 (IntPtr source, SockaddrIn6 destination);
+
+               public static bool TryCopy (IntPtr source, SockaddrIn6 destination)
+               {
+                       return ToSockaddrIn6 (source, destination) == 0;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddrType")]
+               private static extern int FromSockaddrType (SockaddrType value, out Int32 rval);
+
+               internal static bool TryFromSockaddrType (SockaddrType value, out Int32 rval)
+               {
+                       return FromSockaddrType (value, out rval) == 0;
+               }
+
+               internal static Int32 FromSockaddrType (SockaddrType value)
+               {
+                       Int32 rval;
+                       if (FromSockaddrType (value, out rval) == -1)
+                               ThrowArgumentException (value);
+                       return rval;
+               }
+
+               [DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddrType")]
+               private static extern int ToSockaddrType (Int32 value, out SockaddrType rval);
+
+               internal static bool TryToSockaddrType (Int32 value, out SockaddrType rval)
+               {
+                       return ToSockaddrType (value, out rval) == 0;
+               }
+
+               internal static SockaddrType ToSockaddrType (Int32 value)
+               {
+                       SockaddrType rval;
+                       if (ToSockaddrType (value, out rval) == -1)
+                               ThrowArgumentException (value);
+                       return rval;
+               }
+
                [DllImport (LIB, EntryPoint="Mono_Posix_FromSysconfName")]
                private static extern int FromSysconfName (SysconfName value, out Int32 rval);
 
index 8b1246e617eb839c15ca494ea28e54d4566ebeb8..74af55b2fd6c2eccc24007858195507f240b0fb4 100644 (file)
@@ -821,6 +821,9 @@ namespace Mono.Unix.Native {
                AF_ALG        = 38,  /* Algorithm sockets. */
                AF_NFC        = 39,  /* NFC sockets. */
                AF_VSOCK      = 40,  /* vSockets. */
+
+               // Value used when a syscall returns an unknown address family value
+               Unknown       = 65536,
        }
 
        [Map]
@@ -907,6 +910,20 @@ namespace Mono.Unix.Native {
                SHUT_RDWR = 0x03,   /* No more receptions or transmissions. */
        }
 
+       // Used by libMonoPosixHelper to distinguish between different sockaddr types
+       [Map]
+       enum SockaddrType : int {
+               Invalid,
+               SockaddrStorage,
+               SockaddrUn,
+               Sockaddr,
+               SockaddrIn,
+               SockaddrIn6,
+
+               // Flag to indicate that this Sockaddr must be wrapped with a _SockaddrDynamic wrapper
+               MustBeWrapped = 0x8000,
+       }
+
        #endregion
 
        #region Structures
@@ -1416,6 +1433,144 @@ namespace Mono.Unix.Native {
                public int l_linger;
        }
 
+       [Map]
+       [StructLayout (LayoutKind.Sequential)]
+       [CLSCompliant (false)]
+       public struct InAddr : IEquatable<InAddr> {
+               public uint s_addr;
+
+               public unsafe InAddr (byte b0, byte b1, byte b2, byte b3)
+               {
+                       s_addr = 0;
+                       fixed (uint* ptr = &s_addr) {
+                               byte* bytePtr = (byte*) ptr;
+                               bytePtr[0] = b0;
+                               bytePtr[1] = b1;
+                               bytePtr[2] = b2;
+                               bytePtr[3] = b3;
+                       }
+               }
+
+               public unsafe InAddr (byte[] buffer)
+               {
+                       if (buffer.Length != 4)
+                               throw new ArgumentException ("buffer.Length != 4", "buffer");
+                       s_addr = 0;
+                       fixed (uint* ptr = &s_addr)
+                               Marshal.Copy (buffer, 0, (IntPtr) ptr, 4);
+               }
+
+               public unsafe void CopyFrom (byte[] source, int startIndex)
+               {
+                       fixed (uint* ptr = &s_addr)
+                               Marshal.Copy (source, startIndex, (IntPtr) ptr, 4);
+               }
+
+               public unsafe void CopyTo (byte[] destination, int startIndex)
+               {
+                       fixed (uint* ptr = &s_addr)
+                               Marshal.Copy ((IntPtr) ptr, destination, startIndex, 4);
+               }
+
+               public unsafe byte this[int index] {
+                       get {
+                               if (index < 0 || index >= 4)
+                                       throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 4");
+                               fixed (uint* ptr = &s_addr)
+                                       return ((byte*) ptr)[index];
+                       }
+                       set {
+                               if (index < 0 || index >= 4)
+                                       throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 4");
+                               fixed (uint* ptr = &s_addr)
+                                       ((byte*) ptr)[index] = value;
+                       }
+               }
+
+               public override string ToString ()
+               {
+                       return NativeConvert.ToIPAddress (this).ToString ();
+               }
+
+               public override int GetHashCode ()
+               {
+                       return s_addr.GetHashCode ();
+               }
+               public override bool Equals (object obj)
+               {
+                       if (!(obj is InAddr))
+                               return false;
+                       return Equals ((InAddr) obj);
+               }
+               public bool Equals (InAddr value)
+               {
+                       return s_addr == value.s_addr;
+               }
+       }
+
+       [Map]
+       [StructLayout (LayoutKind.Sequential)]
+       public struct In6Addr : IEquatable<In6Addr> {
+               ulong addr0;
+               ulong addr1;
+
+               public unsafe In6Addr (byte[] buffer)
+               {
+                       if (buffer.Length != 16)
+                               throw new ArgumentException ("buffer.Length != 16", "buffer");
+                       addr0 = addr1 = 0;
+                       fixed (ulong* ptr = &addr0)
+                               Marshal.Copy (buffer, 0, (IntPtr) ptr, 16);
+               }
+
+               public unsafe void CopyFrom (byte[] source, int startIndex)
+               {
+                       fixed (ulong* ptr = &addr0)
+                               Marshal.Copy (source, startIndex, (IntPtr) ptr, 16);
+               }
+
+               public unsafe void CopyTo (byte[] destination, int startIndex)
+               {
+                       fixed (ulong* ptr = &addr0)
+                               Marshal.Copy ((IntPtr) ptr, destination, startIndex, 16);
+               }
+
+               public unsafe byte this[int index] {
+                       get {
+                               if (index < 0 || index >= 16)
+                                       throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 16");
+                               fixed (ulong* ptr = &addr0)
+                                       return ((byte*) ptr)[index];
+                       }
+                       set {
+                               if (index < 0 || index >= 16)
+                                       throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 16");
+                               fixed (ulong* ptr = &addr0)
+                                       ((byte*) ptr)[index] = value;
+                       }
+               }
+
+               public override string ToString ()
+               {
+                       return NativeConvert.ToIPAddress (this).ToString ();
+               }
+
+               public override int GetHashCode ()
+               {
+                       return addr0.GetHashCode () ^ addr1.GetHashCode ();
+               }
+               public override bool Equals (object obj)
+               {
+                       if (!(obj is In6Addr))
+                               return false;
+                       return Equals ((In6Addr) obj);
+               }
+               public bool Equals (In6Addr value)
+               {
+                       return addr0 == value.addr0 && addr1 == value.addr1;
+               }
+       }
+
        #endregion
 
        #region Classes
@@ -1710,6 +1865,522 @@ namespace Mono.Unix.Native {
                }
        }
 
+       // This struct is used by the native code.
+       // Its layout must be the same as the start of the Sockaddr class and the start of the _SockaddrDynamic struct
+       [Map]
+       [StructLayout (LayoutKind.Sequential)]
+       internal struct _SockaddrHeader {
+               internal SockaddrType type;
+               internal UnixAddressFamily sa_family;
+       }
+
+       // Base class for all Sockaddr types.
+       // This class is not abstract, instances of this class can be used to determine the sa_family value.
+       // This class and all classes which are deriving from it and are passed to the native code have to be blittable.
+       [CLSCompliant (false)]
+       [StructLayout (LayoutKind.Sequential)]
+       public class Sockaddr {
+               // Note: the layout of the first members must match the layout of struct _SockaddrHeader
+               // 'type' must be the first field of the class as it is used to find the address of the class itself
+               internal SockaddrType type;
+               internal UnixAddressFamily _sa_family;
+
+               public UnixAddressFamily sa_family {
+                       get { return _sa_family; }
+                       set { _sa_family = value; }
+               }
+
+               public Sockaddr ()
+               {
+                       this.type = SockaddrType.Sockaddr;
+                       this.sa_family = UnixAddressFamily.AF_UNSPEC;
+               }
+
+               internal Sockaddr (SockaddrType type, UnixAddressFamily sa_family)
+               {
+                       this.type = type;
+                       this.sa_family = sa_family;
+               }
+
+               [DllImport (Syscall.MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Sockaddr_GetNativeSize")]
+               static extern unsafe int GetNativeSize (_SockaddrHeader* address, out long size);
+
+               internal unsafe long GetNativeSize ()
+               {
+                       long size;
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (this).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (this)) {
+                               var dyn = new _SockaddrDynamic (this, data, useMaxLength: false);
+                               if (GetNativeSize (Sockaddr.GetNative (&dyn, addr), out size) != 0)
+                                               throw new ArgumentException ("Failed to get size of native struct", "this");
+                       }
+                       return size;
+               }
+
+
+               // In order to create a wrapper for a syscall which accepts a "struct sockaddr" argument but does not modify it, use:
+
+               // fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+               // fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+               //     var dyn = new _SockaddrDynamic (address, data, useMaxLength: false);
+               //     return sys_syscall (..., Sockaddr.GetNative (&dyn, addr));
+               // }
+
+               // For syscalls which modify the argument, use:
+
+               // fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+               // fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+               //     var dyn = new _SockaddrDynamic (address, data, useMaxLength: true);
+               //     rettype r = sys_syscall (..., Sockaddr.GetNative (&dyn, addr));
+               //     dyn.Update (address);
+               //     return r;
+               // }
+
+               // This sequence will handle
+               // - normal Sockaddrs like SockaddrIn and SockaddrIn6 which will be passed directly,
+               // - sockaddrs like SockaddrUn and SockaddrStorage which need a wrapper and
+               // - null (which will be passed as null)
+               // without any heap memory allocations.
+
+
+               // This is a fake Sockaddr which is passed to the fixed() statement if the address was null.
+               // Sockaddr.GetNative() will return a null pointer for this Sockaddr.
+               static Sockaddr nullSockaddr = new Sockaddr ();
+
+               internal static Sockaddr GetAddress (Sockaddr address)
+               {
+                       if (address == null)
+                               return nullSockaddr;
+                       else
+                               return address;
+               }
+
+               internal static unsafe _SockaddrHeader* GetNative (_SockaddrDynamic* dyn, SockaddrType* addr)
+               {
+                       if (dyn->data != null) {
+                               return (_SockaddrHeader*) dyn;
+                       } else {
+                               fixed (SockaddrType* nullType = &nullSockaddr.type)
+                                       if (addr == nullType)
+                                               return null;
+                               return (_SockaddrHeader*) addr;
+                       }
+               }
+
+               // Return an array containing the dynamic data (for SockaddrStorage and SockaddrUn) or null
+               internal static byte[] GetDynamicData (Sockaddr addr)
+               {
+                       if (addr == null)
+                               return null;
+                       return addr.DynamicData ();
+               }
+
+               // This methods is overwritten in SockaddrStorage and SockaddrUn
+               internal virtual byte[] DynamicData ()
+               {
+                       return null;
+               }
+
+               // This methods should only be called for SockaddrStorage and SockaddrUn where they are overwritten
+               internal virtual long GetDynamicLength ()
+               {
+                       throw new NotImplementedException ();
+               }
+
+               internal virtual void SetDynamicLength (long value)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public SockaddrStorage ToSockaddrStorage ()
+               {
+                       var storage = new SockaddrStorage ((int) GetNativeSize ());
+                       storage.SetTo (this);
+                       return storage;
+               }
+
+               public static Sockaddr FromSockaddrStorage (SockaddrStorage storage)
+               {
+                       var ret = new Sockaddr ();
+                       storage.CopyTo (ret);
+                       return ret;
+               }
+       }
+
+       // This struct is required to manually marshal Sockaddr* classes which include an array (currently SockaddrStorage and SockaddrUn).
+       // This is needed because the marshalling code will not work if the classes derived from Sockaddr aren't blittable.
+       [Map]
+       unsafe struct _SockaddrDynamic {
+               // Note: the layout of the first members must match the layout of struct _SockaddrHeader
+               public SockaddrType type;
+               public UnixAddressFamily sa_family;
+               public byte* data;
+               public long len;
+
+               public _SockaddrDynamic (Sockaddr address, byte* data, bool useMaxLength)
+               {
+                       if (data == null) {
+                               // When data is null, no wrapper is needed.
+                               // Initialize everything to zero, Sockaddr.GetNative() will then
+                               // use the Sockaddr structure directly.
+                               this = new _SockaddrDynamic ();
+                               return;
+                       }
+
+                       var dynData = address.DynamicData ();
+
+                       type = address.type & ~SockaddrType.MustBeWrapped;
+                       sa_family = address.sa_family;
+                       this.data = data;
+                       if (useMaxLength) {
+                               len = dynData.Length;
+                       } else {
+                               len = address.GetDynamicLength ();
+                               if (len < 0 || len > dynData.Length)
+                                       throw new ArgumentException ("len < 0 || len > dynData.Length", "address");
+                       }
+               }
+
+               public void Update (Sockaddr address)
+               {
+                       // When data is null, no wrapper was needed.
+                       if (data == null)
+                               return;
+
+                       address.sa_family = sa_family;
+                       address.SetDynamicLength (len);
+               }
+       };
+
+       // This is a class which can store arbitrary sockaddrs, even if they are not known the the Mono.Unix wrapper or the family does not have a corresponding value in the UnixAddressFamily enumeration.
+       [CLSCompliant (false)]
+       public sealed class SockaddrStorage : Sockaddr, IEquatable<SockaddrStorage> {
+               // Note: The sa_family field is ignored when passing a SockaddrStorage to a syscall (but it will be set when a SockaddrStorage is returned from a syscall). Instead of the sa_family field, the value embedded in data is used.
+               public byte[] data { get; set; }
+               public long data_len { get; set; }
+
+               internal override byte[] DynamicData ()
+               {
+                       return data;
+               }
+
+               internal override long GetDynamicLength ()
+               {
+                       return data_len;
+               }
+
+               internal override void SetDynamicLength (long value)
+               {
+                       data_len = value;
+               }
+
+               [DllImport (Syscall.MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_SockaddrStorage_get_size")]
+               static extern int get_size ();
+               static readonly int default_size = get_size ();
+
+               public SockaddrStorage ()
+                       : base (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNSPEC)
+               {
+                       data = new byte[default_size];
+                       data_len = 0;
+               }
+
+               public SockaddrStorage (int size)
+                       : base (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNSPEC)
+               {
+                       data = new byte[size];
+                       data_len = 0;
+               }
+
+               public unsafe void SetTo (Sockaddr address)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+
+                       var size = address.GetNativeSize ();
+                       if (size > data.Length)
+                               data = new byte[size];
+                       fixed (byte* ptr = data)
+                               if (!NativeConvert.TryCopy (address, (IntPtr) ptr))
+                                       throw new ArgumentException ("Failed to convert to native struct", "address");
+                       data_len = size;
+                       sa_family = address.sa_family;
+               }
+
+               public unsafe void CopyTo (Sockaddr address)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+                       if (data_len < 0 || data_len > data.Length)
+                               throw new ArgumentException ("data_len < 0 || data_len > data.Length", "this");
+
+                       fixed (byte* ptr = data)
+                               if (!NativeConvert.TryCopy ((IntPtr) ptr, data_len, address))
+                                       throw new ArgumentException ("Failed to convert from native struct", "this");
+               }
+
+               public override string ToString ()
+               {
+                       var sb = new StringBuilder ();
+                       sb.AppendFormat ("{{sa_family={0}, data_len={1}, data=(", sa_family, data_len);
+                       for (int i = 0; i < data_len; i++) {
+                               if (i != 0)
+                                       sb.Append (" ");
+                               sb.Append (data[i].ToString ("x2"));
+                       }
+                       sb.Append (")");
+                       return sb.ToString ();
+               }
+
+               public override int GetHashCode ()
+               {
+                       unchecked {
+                               int hash = 0x1234;
+                               for (int i = 0; i < data_len; i++)
+                                       hash += i ^ data[i];
+                               return hash;
+                       }
+               }
+
+               public override bool Equals (object obj)
+               {
+                       if (!(obj is SockaddrStorage))
+                               return false;
+                       return Equals ((SockaddrStorage) obj);
+               }
+
+               public bool Equals (SockaddrStorage value)
+               {
+                       if (value == null)
+                               return false;
+                       if (data_len != value.data_len)
+                               return false;
+                       for (int i = 0; i < data_len; i++)
+                               if (data[i] != value.data[i])
+                                       return false;
+                       return true;
+               }
+       }
+
+       [CLSCompliant (false)]
+       public sealed class SockaddrUn : Sockaddr, IEquatable<SockaddrUn> {
+               public UnixAddressFamily sun_family { // AF_UNIX
+                       get { return sa_family; }
+                       set { sa_family = value; }
+               }
+               public byte[] sun_path { get; set; }
+               public long sun_path_len { get; set; } // Indicates how many bytes of sun_path are valid. Must not be larger than sun_path.Length.
+
+               internal override byte[] DynamicData ()
+               {
+                       return sun_path;
+               }
+
+               internal override long GetDynamicLength ()
+               {
+                       return sun_path_len;
+               }
+
+               internal override void SetDynamicLength (long value)
+               {
+                       sun_path_len = value;
+               }
+
+               [DllImport (Syscall.MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_SockaddrUn_get_sizeof_sun_path")]
+               static extern int get_sizeof_sun_path ();
+               static readonly int sizeof_sun_path = get_sizeof_sun_path ();
+
+               public SockaddrUn ()
+                       : base (SockaddrType.SockaddrUn | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNIX)
+               {
+                       sun_path = new byte[sizeof_sun_path];
+                       sun_path_len = 0;
+               }
+
+               public SockaddrUn (int size)
+                       : base (SockaddrType.SockaddrUn | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNIX)
+               {
+                       sun_path = new byte[size];
+                       sun_path_len = 0;
+               }
+
+               public SockaddrUn (string path, bool linuxAbstractNamespace = false)
+                       : base (SockaddrType.SockaddrUn | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNIX)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException ("path");
+                       var bytes = UnixEncoding.Instance.GetBytes (path);
+                       if (linuxAbstractNamespace) {
+                               sun_path = new byte[1 + bytes.Length];
+                               Array.Copy (bytes, 0, sun_path, 1, bytes.Length);
+                       } else {
+                               sun_path = bytes;
+                       }
+                       sun_path_len = sun_path.Length;
+               }
+
+               public bool IsLinuxAbstractNamespace {
+                       get {
+                               return sun_path_len > 0 && sun_path[0] == 0;
+                       }
+               }
+
+               public string Path {
+                       get {
+                               var offset = IsLinuxAbstractNamespace ? 1 : 0;
+                               // Remove data after null terminator
+                               int length;
+                               for (length = 0; offset + length < sun_path_len; length++)
+                                       if (sun_path[offset + length] == 0)
+                                               break;
+                               return UnixEncoding.Instance.GetString (sun_path, offset, length);
+                       }
+               }
+
+               public override string ToString ()
+               {
+                       return string.Format ("{{sa_family={0}, sun_path=\"{1}{2}\"}}", sa_family, IsLinuxAbstractNamespace ? "\\0" : "", Path);
+               }
+
+               public static new SockaddrUn FromSockaddrStorage (SockaddrStorage storage)
+               {
+                       // This will make the SockaddrUn larger than it needs to be (because
+                       // storage.data_len includes the sun_family field), but it will be
+                       // large enough.
+                       var ret = new SockaddrUn ((int) storage.data_len);
+                       storage.CopyTo (ret);
+                       return ret;
+               }
+
+               public override int GetHashCode ()
+               {
+                       return sun_family.GetHashCode () ^ IsLinuxAbstractNamespace.GetHashCode () ^ Path.GetHashCode ();
+               }
+
+               public override bool Equals (object obj)
+               {
+                       if (!(obj is SockaddrUn))
+                               return false;
+                       return Equals ((SockaddrUn) obj);
+               }
+
+               public bool Equals (SockaddrUn value)
+               {
+                       if (value == null)
+                               return false;
+                       return sun_family == value.sun_family
+                               && IsLinuxAbstractNamespace == value.IsLinuxAbstractNamespace
+                               && Path == value.Path;
+               }
+       }
+
+       [Map ("struct sockaddr_in")]
+       [CLSCompliant (false)]
+       [StructLayout (LayoutKind.Sequential)]
+       public sealed class SockaddrIn : Sockaddr, IEquatable<SockaddrIn> {
+               public UnixAddressFamily sin_family { // AF_INET
+                       get { return sa_family; }
+                       set { sa_family = value; }
+               }
+               public ushort sin_port;   // Port number.
+               public InAddr sin_addr;   // IP address.
+
+               public SockaddrIn ()
+                       : base (SockaddrType.SockaddrIn, UnixAddressFamily.AF_INET)
+               {
+               }
+
+               public override string ToString ()
+               {
+                       return string.Format ("{{sin_family={0}, sin_port=htons({1}), sin_addr={2}}}", sa_family, Syscall.ntohs(sin_port), sin_addr);
+               }
+
+               public static new SockaddrIn FromSockaddrStorage (SockaddrStorage storage)
+               {
+                       var ret = new SockaddrIn ();
+                       storage.CopyTo (ret);
+                       return ret;
+               }
+
+               public override int GetHashCode ()
+               {
+                       return sin_family.GetHashCode () ^ sin_port.GetHashCode () ^ sin_addr.GetHashCode ();
+               }
+
+               public override bool Equals (object obj)
+               {
+                       if (!(obj is SockaddrIn))
+                               return false;
+                       return Equals ((SockaddrIn) obj);
+               }
+
+               public bool Equals (SockaddrIn value)
+               {
+                       if (value == null)
+                               return false;
+                       return sin_family == value.sin_family
+                               && sin_port == value.sin_port
+                               && sin_addr.Equals (value.sin_addr);
+               }
+       }
+
+       [Map ("struct sockaddr_in6")]
+       [CLSCompliant (false)]
+       [StructLayout (LayoutKind.Sequential)]
+       public sealed class SockaddrIn6 : Sockaddr, IEquatable<SockaddrIn6> {
+               public UnixAddressFamily sin6_family { // AF_INET6
+                       get { return sa_family; }
+                       set { sa_family = value; }
+               }
+               public ushort  sin6_port;     // Port number.
+               public uint    sin6_flowinfo; // IPv6 traffic class and flow information.
+               public In6Addr sin6_addr;     // IPv6 address.
+               public uint    sin6_scope_id; // Set of interfaces for a scope.
+
+               public SockaddrIn6 ()
+                       : base (SockaddrType.SockaddrIn6, UnixAddressFamily.AF_INET6)
+               {
+               }
+
+               public override string ToString ()
+               {
+                       return string.Format ("{{sin6_family={0}, sin6_port=htons({1}), sin6_flowinfo={2}, sin6_addr={3}, sin6_scope_id={4}}}", sa_family, Syscall.ntohs (sin6_port), sin6_flowinfo, sin6_addr, sin6_scope_id);
+               }
+
+               public static new SockaddrIn6 FromSockaddrStorage (SockaddrStorage storage)
+               {
+                       var ret = new SockaddrIn6 ();
+                       storage.CopyTo (ret);
+                       return ret;
+               }
+
+               public override int GetHashCode ()
+               {
+                       return sin6_family.GetHashCode () ^ sin6_port.GetHashCode () ^ sin6_flowinfo.GetHashCode () ^ sin6_addr.GetHashCode () ^ sin6_scope_id.GetHashCode ();
+               }
+
+               public override bool Equals (object obj)
+               {
+                       if (!(obj is SockaddrIn6))
+                               return false;
+                       return Equals ((SockaddrIn6) obj);
+               }
+
+               public bool Equals (SockaddrIn6 value)
+               {
+                       if (value == null)
+                               return false;
+                       return sin6_family == value.sin6_family
+                               && sin6_port == value.sin6_port
+                               && sin6_flowinfo == value.sin6_flowinfo
+                               && sin6_addr.Equals (value.sin6_addr)
+                               && sin6_scope_id == value.sin6_scope_id;
+               }
+       }
+
        //
        // 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.
@@ -4545,6 +5216,33 @@ namespace Mono.Unix.Native {
                }
                #endregion
 
+               #region <arpa/inet.h> Declarations
+               //
+               // <arpa/inet.h>
+               //
+
+               // htonl(3)
+               //    uint32_t htonl(uint32_t hostlong);
+               [DllImport (LIBC)]
+               public static extern uint htonl(uint hostlong);
+
+               // htons(3)
+               //    uint16_t htons(uint16_t hostshort);
+               [DllImport (LIBC)]
+               public static extern ushort htons(ushort hostshort);
+
+               // ntohl(3)
+               //    uint32_t ntohl(uint32_t netlong);
+               [DllImport (LIBC)]
+               public static extern uint ntohl(uint netlong);
+
+               // ntohs(3)
+               //    uint16_t ntohs(uint16_t netshort);
+               [DllImport (LIBC)]
+               public static extern ushort ntohs(ushort netshort);
+
+               #endregion
+
                #region <socket.h> Declarations
                //
                // <socket.h>
@@ -4780,6 +5478,165 @@ namespace Mono.Unix.Native {
                                return send (socket, ptr, length, flags);
                }
 
+               // bind(2)
+               //    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_bind")]
+               static extern unsafe int sys_bind (int socket, _SockaddrHeader* address);
+
+               public static unsafe int bind (int socket, Sockaddr address)
+               {
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: false);
+                               return sys_bind (socket, Sockaddr.GetNative (&dyn, addr));
+                       }
+               }
+
+               // connect(2)
+               //    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_connect")]
+               static extern unsafe int sys_connect (int socket, _SockaddrHeader* address);
+
+               public static unsafe int connect (int socket, Sockaddr address)
+               {
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: false);
+                               return sys_connect (socket, Sockaddr.GetNative (&dyn, addr));
+                       }
+               }
+
+               // accept(2)
+               //    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_accept")]
+               static extern unsafe int sys_accept (int socket, _SockaddrHeader* address);
+
+               public static unsafe int accept (int socket, Sockaddr address)
+               {
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: true);
+                               int r = sys_accept (socket, Sockaddr.GetNative (&dyn, addr));
+                               dyn.Update (address);
+                               return r;
+                       }
+               }
+
+               // accept4(2)
+               //    int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_accept4")]
+               static extern unsafe int sys_accept4 (int socket, _SockaddrHeader* address, int flags);
+
+               public static unsafe int accept4 (int socket, Sockaddr address, UnixSocketFlags flags)
+               {
+                       var _flags = NativeConvert.FromUnixSocketFlags (flags);
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: true);
+                               int r = sys_accept4 (socket, Sockaddr.GetNative (&dyn, addr), _flags);
+                               dyn.Update (address);
+                               return r;
+                       }
+               }
+
+               // getpeername(2)
+               //    int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_getpeername")]
+               static extern unsafe int sys_getpeername (int socket, _SockaddrHeader* address);
+
+               public static unsafe int getpeername (int socket, Sockaddr address)
+               {
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: true);
+                               int r = sys_getpeername (socket, Sockaddr.GetNative (&dyn, addr));
+                               dyn.Update (address);
+                               return r;
+                       }
+               }
+
+               // getsockname(2)
+               //    int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_getsockname")]
+               static extern unsafe int sys_getsockname (int socket, _SockaddrHeader* address);
+
+               public static unsafe int getsockname (int socket, Sockaddr address)
+               {
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: true);
+                               int r = sys_getsockname (socket, Sockaddr.GetNative (&dyn, addr));
+                               dyn.Update (address);
+                               return r;
+                       }
+               }
+
+               // recvfrom(2)
+               //    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_recvfrom")]
+               static extern unsafe long sys_recvfrom (int socket, void *buffer, ulong length, int flags, _SockaddrHeader* address);
+
+               public static unsafe long recvfrom (int socket, void *buffer, ulong length, MessageFlags flags, Sockaddr address)
+               {
+                       int _flags = NativeConvert.FromMessageFlags (flags);
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: true);
+                               long r = sys_recvfrom (socket, buffer, length, _flags, Sockaddr.GetNative (&dyn, addr));
+                               dyn.Update (address);
+                               return r;
+                       }
+               }
+
+               public static unsafe long recvfrom (int socket, IntPtr buffer, ulong length, MessageFlags flags, Sockaddr address)
+               {
+                       return recvfrom (socket, (void*) buffer, length, flags, address);
+               }
+
+               public static unsafe long recvfrom (int socket, byte[] buffer, ulong length, MessageFlags flags, Sockaddr address)
+               {
+                       if (length > (ulong) buffer.LongLength)
+                               throw new ArgumentOutOfRangeException ("length", "length > buffer.LongLength");
+                       fixed (byte* ptr = buffer)
+                               return recvfrom (socket, ptr, length, flags, address);
+               }
+
+               // sendto(2)
+               //    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_sendto")]
+               static extern unsafe long sys_sendto (int socket, void *message, ulong length, int flags, _SockaddrHeader* address);
+
+               public static unsafe long sendto (int socket, void *message, ulong length, MessageFlags flags, Sockaddr address)
+               {
+                       int _flags = NativeConvert.FromMessageFlags (flags);
+                       fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type)
+                       fixed (byte* data = Sockaddr.GetDynamicData (address)) {
+                               var dyn = new _SockaddrDynamic (address, data, useMaxLength: false);
+                               return sys_sendto (socket, message, length, _flags, Sockaddr.GetNative (&dyn, addr));
+                       }
+               }
+
+               public static unsafe long sendto (int socket, IntPtr message, ulong length, MessageFlags flags, Sockaddr address)
+               {
+                       return sendto (socket, (void*) message, length, flags, address);
+               }
+
+               public static unsafe long sendto (int socket, byte[] message, ulong length, MessageFlags flags, Sockaddr address)
+               {
+                       if (length > (ulong) message.LongLength)
+                               throw new ArgumentOutOfRangeException ("length", "length > message.LongLength");
+                       fixed (byte* ptr = message)
+                               return sendto (socket, ptr, length, flags, address);
+               }
+
                #endregion
        }
 
@@ -4787,3 +5644,8 @@ namespace Mono.Unix.Native {
 }
 
 // vim: noexpandtab
+// Local Variables: 
+// tab-width: 4
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// End: 
index 36a8d233c176c6e157008151324ed8a841ed0f15..aac0a58a688e93000bacc99974f94903b3177bb4 100644 (file)
@@ -98,7 +98,7 @@ namespace MonoTests.Mono.Unix.Native
                }
 
                [Test]
-               public void Socket ()
+               public void TestSocket ()
                {
                        int socket;
                        if ((socket = Syscall.socket (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0)) < 0)
@@ -206,6 +206,389 @@ namespace MonoTests.Mono.Unix.Native
                                Assert.AreEqual (ret, 0);
                        });
                }
+
+               [Test]
+               public unsafe void ByteOrder ()
+               {
+                       ushort val1 = Syscall.htons (0x1234);
+                       byte* ptr1 = (byte*) &val1;
+                       Assert.AreEqual (ptr1[0], 0x12);
+                       Assert.AreEqual (ptr1[1], 0x34);
+
+                       uint val2 = Syscall.htonl (0x6789abcd);
+                       byte* ptr2 = (byte*) &val2;
+                       Assert.AreEqual (ptr2[0], 0x67);
+                       Assert.AreEqual (ptr2[1], 0x89);
+                       Assert.AreEqual (ptr2[2], 0xab);
+                       Assert.AreEqual (ptr2[3], 0xcd);
+
+                       ptr1[0] = 0xfe;
+                       ptr1[1] = 0xdc;
+                       Assert.AreEqual (Syscall.ntohs (val1), 0xfedc);
+
+                       ptr2[0] = 0x76;
+                       ptr2[1] = 0x54;
+                       ptr2[2] = 0x32;
+                       ptr2[3] = 0x10;
+                       Assert.AreEqual (Syscall.ntohl (val2), 0x76543210);
+               }
+
+               [Test]
+               public void InAddr ()
+               {
+                       var ip = IPAddress.Loopback;
+                       var inAddr = NativeConvert.ToInAddr (ip);
+                       Assert.AreEqual (ip, NativeConvert.ToIPAddress (inAddr));
+                       Assert.AreEqual (0x7f000001, Syscall.ntohl (inAddr.s_addr));
+
+                       Assert.AreEqual ("127.0.0.1", inAddr.ToString ());
+               }
+
+               [Test]
+               public void In6Addr ()
+               {
+                       if (!Socket.OSSupportsIPv6)
+                               Assert.Ignore ("OS does not support IPv6.");
+
+                       var ip6 = IPAddress.IPv6Loopback;
+                       var in6Addr = NativeConvert.ToIn6Addr (ip6);
+                       Assert.AreEqual (ip6, NativeConvert.ToIPAddress (in6Addr));
+                       Assert.AreEqual (1, in6Addr[15]);
+
+                       Assert.AreEqual ("::1", in6Addr.ToString ());
+               }
+
+               [Test]
+               public void SockaddrUnTest ()
+               {
+                       var address1 = new SockaddrUn ("/tmp/foo");
+                       Assert.AreEqual (address1.Path, "/tmp/foo");
+                       Assert.IsFalse (address1.IsLinuxAbstractNamespace);
+
+                       var storage = address1.ToSockaddrStorage ();
+                       var address2 = SockaddrUn.FromSockaddrStorage (storage);
+                       Assert.AreEqual (address1, address2);
+
+                       var sockaddr = Sockaddr.FromSockaddrStorage (storage);
+                       Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
+
+                       var address3 = new SockaddrUn ("/tmp/bar", linuxAbstractNamespace:true);
+                       Assert.AreEqual (address3.Path, "/tmp/bar");
+                       Assert.IsTrue (address3.IsLinuxAbstractNamespace);
+
+                       var address4 = new SockaddrUn (new string ('X', 9000));
+                       Assert.AreEqual (address4.Path, new string ('X', 9000));
+                       Assert.IsFalse (address4.IsLinuxAbstractNamespace);
+                       var storage2 = address4.ToSockaddrStorage ();
+                       var address5 = SockaddrUn.FromSockaddrStorage (storage2);
+                       Assert.AreEqual (address4, address5);
+                       // Test the malloc() path for long SockaddrUn adresses (the syscalls will fail because the fd is invalid and because the path is too long)
+                       Syscall.bind (-1, address4);
+                       Syscall.getsockname (-1, address4);
+
+                       Assert.AreEqual ("{sa_family=AF_UNIX, sun_path=\"/tmp/foo\"}", address1.ToString ());
+                       Assert.AreEqual ("{sa_family=AF_UNIX, sun_path=\"\\0/tmp/bar\"}", address3.ToString ());
+               }
+
+               [Test]
+               public void SockaddrInTest ()
+               {
+                       var address1 = new SockaddrIn {
+                               sin_family = UnixAddressFamily.AF_INET,
+                               sin_port = Syscall.htons (5678),
+                               sin_addr = NativeConvert.ToInAddr (IPAddress.Loopback),
+                       };
+
+                       var storage = address1.ToSockaddrStorage ();
+                       var address2 = SockaddrIn.FromSockaddrStorage (storage);
+                       Assert.AreEqual (address1, address2);
+
+                       var sockaddr = Sockaddr.FromSockaddrStorage (storage);
+                       Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
+
+                       var storage2 = storage.ToSockaddrStorage ();
+                       Assert.AreEqual (storage, storage2);
+
+                       var storage3 = new SockaddrStorage (123);
+                       storage2.CopyTo (storage3);
+                       Assert.AreEqual (storage, storage3);
+
+                       Assert.AreEqual ("{sin_family=AF_INET, sin_port=htons(5678), sin_addr=127.0.0.1}", address1.ToString ());
+               }
+
+               [Test]
+               public void SockaddrIn6Test ()
+               {
+                       if (!Socket.OSSupportsIPv6)
+                               Assert.Ignore ("OS does not support IPv6.");
+
+                       var address1 = new SockaddrIn6 {
+                               sin6_family = UnixAddressFamily.AF_INET6,
+                               sin6_port = Syscall.htons (1234),
+                               sin6_flowinfo = 2,
+                               sin6_addr = NativeConvert.ToIn6Addr (IPAddress.IPv6Loopback),
+                               sin6_scope_id = 3
+                       };
+
+                       var storage = address1.ToSockaddrStorage ();
+                       var address2 = SockaddrIn6.FromSockaddrStorage (storage);
+                       Assert.AreEqual (address1, address2);
+
+                       var sockaddr = Sockaddr.FromSockaddrStorage (storage);
+                       Assert.AreEqual (sockaddr.sa_family, address1.sa_family);
+
+                       Assert.AreEqual ("{sin6_family=AF_INET6, sin6_port=htons(1234), sin6_flowinfo=2, sin6_addr=::1, sin6_scope_id=3}", address1.ToString ());
+               }
+
+               [Test]
+               public void BindConnect ()
+               {
+                       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);
+
+
+                               // Connect so2 to so1
+                               var remoteAddress = new SockaddrIn {
+                                       sin_family = UnixAddressFamily.AF_INET,
+                                       sin_port = Syscall.htons (port),
+                                       sin_addr = new InAddr (127, 0, 0, 1),
+                               };
+                               if (Syscall.connect (so2, remoteAddress) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               // Verify peer address using getpeername()
+                               var address2 = new SockaddrIn ();
+                               if (Syscall.getpeername (so2, address2) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               Assert.AreEqual (address2.sa_family, UnixAddressFamily.AF_INET);
+                               Assert.AreEqual (remoteAddress.sin_port, address2.sin_port);
+                               Assert.AreEqual (remoteAddress.sin_addr, address2.sin_addr);
+
+                               // Send and receive a few bytes
+                               long ret;
+                               var buffer1 = new byte[] { 42, 43, 44 };
+                               ret = Syscall.send (so2, buffer1, (ulong) buffer1.Length, 0);
+                               if (ret < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               var buffer2 = new byte[1024];
+                               ret = Syscall.recv (so1, buffer2, (ulong) buffer2.Length, 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 void IPv6 ()
+               {
+                       if (!Socket.OSSupportsIPv6)
+                               Assert.Ignore ("OS does not support IPv6.");
+
+                       var address = new SockaddrIn6 {
+                               sin6_family = UnixAddressFamily.AF_INET6,
+                               sin6_port = Syscall.htons (0),
+                               sin6_addr = NativeConvert.ToIn6Addr (IPAddress.IPv6Loopback),
+                       };
+                       WithSockets (UnixAddressFamily.AF_INET6, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
+                               if (Syscall.bind (so1, address) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               var address1Stor = new SockaddrStorage ();
+                               if (Syscall.getsockname (so1, address1Stor) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               var address1 = new SockaddrIn6 ();
+                               address1Stor.CopyTo (address1);
+
+                               // Check getsockname(socket, null)
+                               if (Syscall.getsockname (so1, null) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               var address2 = new SockaddrIn6 ();
+                               if (Syscall.getsockname (so1, address2) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               Assert.AreEqual (address1, address2);
+                               Assert.IsTrue (Syscall.ntohs (address1.sin6_port) != 0);
+                               address1.sin6_port = 0;
+                               Assert.AreEqual (address, address1);
+
+                               var address3 = new Sockaddr ();
+                               if (Syscall.getsockname (so1, address3) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               Assert.AreEqual (address.sa_family, address3.sa_family);
+
+                               // Try to store a sockaddr_in6 into a Sockaddr. Should fail because sockaddr_in6 should be larger than sockaddr_in
+                               var address4 = new SockaddrIn ();
+                               if (Syscall.getsockname (so1, address4) == 0)
+                                       Assert.Fail ("getsockname() should have failed");
+                               Assert.AreEqual (Errno.ENOBUFS, Stdlib.GetLastError ());
+                       });
+               }
+
+               [Test]
+               public void UnixAccept ()
+               {
+                       var address = new SockaddrUn (TempFolder + "/socket1");
+                       var address2 = SockaddrUn.FromSockaddrStorage (address.ToSockaddrStorage ());
+                       Assert.AreEqual (address, address2);
+
+                       WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
+                               if (Syscall.bind (so1, address) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               if (Syscall.listen (so1, 5) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               if (Syscall.connect (so2, address) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               var address3 = new SockaddrUn ();
+                               if (Syscall.getsockname (so1, address3) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               Assert.AreEqual (address, address3);
+
+                               var address4 = new SockaddrStorage ();
+                               if (Syscall.getsockname (so1, address4) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               Assert.AreEqual (UnixAddressFamily.AF_UNIX, address4.sa_family);
+                               Assert.AreEqual (address3, SockaddrUn.FromSockaddrStorage (address4));
+
+                               var address5 = new SockaddrUn ();
+                               if (Syscall.getsockname (so1, address5) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               Assert.AreEqual (UnixAddressFamily.AF_UNIX, address5.sa_family);
+
+                               // Check getsockname(socket, null)
+                               if (Syscall.getsockname (so1, null) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               int so3;
+                               var remote = new SockaddrUn ();
+                               if ((so3 = Syscall.accept (so1, remote)) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               try {
+                                       // Send and receive a few bytes
+                                       long ret;
+                                       var buffer1 = new byte[] { 42, 43, 44 };
+                                       ret = Syscall.send (so2, buffer1, (ulong) buffer1.Length, 0);
+                                       if (ret < 0)
+                                               UnixMarshal.ThrowExceptionForLastError ();
+
+                                       var buffer2 = new byte[1024];
+                                       ret = Syscall.recv (so3, buffer2, (ulong) buffer2.Length, 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]);
+                               } finally {
+                                       if (Syscall.close (so3) < 0)
+                                               UnixMarshal.ThrowExceptionForLastError ();
+                               }
+                       });
+               }
+
+               [Test]
+               public void Accept4 ()
+               {
+                       WithSockets (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0, (so1, so2) => {
+                               var address = new SockaddrUn (TempFolder + "/socket2");
+                               if (Syscall.bind (so1, address) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               if (Syscall.listen (so1, 5) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               if (Syscall.connect (so2, address) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               int so3;
+                               var remote = new SockaddrUn ();
+                               if ((so3 = Syscall.accept4 (so1, remote, UnixSocketFlags.SOCK_CLOEXEC | UnixSocketFlags.SOCK_NONBLOCK)) < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               try {
+                                       int _flags;
+                                       if ((_flags = Syscall.fcntl (so3, FcntlCommand.F_GETFL)) < 0)
+                                               UnixMarshal.ThrowExceptionForLastError ();
+                                       var flags = NativeConvert.ToOpenFlags (_flags);
+                                       Assert.IsTrue ((flags & OpenFlags.O_NONBLOCK) != 0);
+
+                                       int _flagsFD;
+                                       if ((_flagsFD = Syscall.fcntl (so3, FcntlCommand.F_GETFD)) < 0)
+                                               UnixMarshal.ThrowExceptionForLastError ();
+                                       // FD_CLOEXEC must be set
+                                       //var flagsFD = NativeConvert.ToFdFlags (_flagsFD);
+                                       //Assert.IsTrue ((flagsFD & FdFlags.FD_CLOEXEC) != 0);
+                                       Assert.IsTrue (_flagsFD != 0);
+                               } finally {
+                                       if (Syscall.close (so3) < 0)
+                                               UnixMarshal.ThrowExceptionForLastError ();
+                               }
+                       });
+               }
+
+               [Test]
+               public void SendToRecvFrom ()
+               {
+                       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 };
+                               ret = Syscall.sendto (so2, buffer1, (ulong) buffer1.Length, 0, remoteAddress);
+                               if (ret < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+
+                               var senderAddress = new SockaddrIn ();
+                               var buffer2 = new byte[1024];
+                               ret = Syscall.recvfrom (so1, buffer2, (ulong) buffer2.Length, 0, senderAddress);
+                               if (ret < 0)
+                                       UnixMarshal.ThrowExceptionForLastError ();
+                               Assert.AreEqual (senderAddress.sa_family, UnixAddressFamily.AF_INET);
+                               Assert.AreEqual (senderAddress.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]);
+                       });
+               }
        }
 }
 
index 79154fc99bbd9b232eb8c4bd1e16119b07d9bb45..be3864cc9dab1facb674ed486098cf0efcf8c846 100644 (file)
@@ -161,7 +161,7 @@ refresh:
        --rename-member=st_mtime=st_mtime_                    \
        --rename-namespace=Mono.Unix.Native=Mono.Posix        \
        --library=MonoPosixHelper                             \
-       $(mcs_topdir)/class/lib/net_4_x/Mono.Posix.dll map
+       $(mcs_topdir_from_srcdir)/class/lib/net_4_x/Mono.Posix.dll map
 
 # Useful if mono is compiled with --enable-shared=no
 patch-libtool:
index ee61ae661d9be7e741c0997fdf7e6de54ccc5d9a..6201c260c93369f1e37c4ceb340fe7c693b9a055 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file was automatically generated by create-native-map from /home/kiesssn/prog/mono/mono/mcs/class/lib/net_4_x/Mono.Posix.dll.
+ * This file was automatically generated by create-native-map from ../mcs/class/lib/net_4_x/Mono.Posix.dll.
  *
  * DO NOT MODIFY.
  */
@@ -5149,6 +5149,172 @@ int Mono_Posix_ToSignum (int x, int *r)
        errno = EINVAL; return -1;
 }
 
+#ifdef HAVE_STRUCT_SOCKADDR_IN
+int
+Mono_Posix_FromSockaddrIn (struct Mono_Posix_SockaddrIn *from, struct sockaddr_in *to)
+{
+       _cnm_return_val_if_overflow (unsigned short, from->sin_port, -1);
+
+       memset (to, 0, sizeof(*to));
+
+       to->sin_port = from->sin_port;
+       if (Mono_Posix_FromInAddr (&from->sin_addr, &to->sin_addr) != 0) {
+               return -1;
+       }
+
+       return 0;
+}
+#endif /* ndef HAVE_STRUCT_SOCKADDR_IN */
+
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN
+int
+Mono_Posix_ToSockaddrIn (struct sockaddr_in *from, struct Mono_Posix_SockaddrIn *to)
+{
+       _cnm_return_val_if_overflow (unsigned short, from->sin_port, -1);
+
+       memset (to, 0, sizeof(*to));
+
+       to->sin_port = from->sin_port;
+       if (Mono_Posix_ToInAddr (&from->sin_addr, &to->sin_addr) != 0) {
+               return -1;
+       }
+
+       return 0;
+}
+#endif /* ndef HAVE_STRUCT_SOCKADDR_IN */
+
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+int
+Mono_Posix_FromSockaddrIn6 (struct Mono_Posix_SockaddrIn6 *from, struct sockaddr_in6 *to)
+{
+       _cnm_return_val_if_overflow (unsigned short, from->sin6_port, -1);
+       _cnm_return_val_if_overflow (unsigned int, from->sin6_flowinfo, -1);
+       _cnm_return_val_if_overflow (unsigned int, from->sin6_scope_id, -1);
+
+       memset (to, 0, sizeof(*to));
+
+       to->sin6_port     = from->sin6_port;
+       to->sin6_flowinfo = from->sin6_flowinfo;
+       if (Mono_Posix_FromIn6Addr (&from->sin6_addr, &to->sin6_addr) != 0) {
+               return -1;
+       }
+       to->sin6_scope_id = from->sin6_scope_id;
+
+       return 0;
+}
+#endif /* ndef HAVE_STRUCT_SOCKADDR_IN6 */
+
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+int
+Mono_Posix_ToSockaddrIn6 (struct sockaddr_in6 *from, struct Mono_Posix_SockaddrIn6 *to)
+{
+       _cnm_return_val_if_overflow (unsigned short, from->sin6_port, -1);
+       _cnm_return_val_if_overflow (unsigned int, from->sin6_flowinfo, -1);
+       _cnm_return_val_if_overflow (unsigned int, from->sin6_scope_id, -1);
+
+       memset (to, 0, sizeof(*to));
+
+       to->sin6_port     = from->sin6_port;
+       to->sin6_flowinfo = from->sin6_flowinfo;
+       if (Mono_Posix_ToIn6Addr (&from->sin6_addr, &to->sin6_addr) != 0) {
+               return -1;
+       }
+       to->sin6_scope_id = from->sin6_scope_id;
+
+       return 0;
+}
+#endif /* ndef HAVE_STRUCT_SOCKADDR_IN6 */
+
+
+int Mono_Posix_FromSockaddrType (int x, int *r)
+{
+       *r = 0;
+       if (x == Mono_Posix_SockaddrType_Invalid)
+#ifdef Invalid
+               {*r = Invalid; return 0;}
+#else /* def Invalid */
+               {errno = EINVAL; return -1;}
+#endif /* ndef Invalid */
+       if (x == Mono_Posix_SockaddrType_MustBeWrapped)
+#ifdef MustBeWrapped
+               {*r = MustBeWrapped; return 0;}
+#else /* def MustBeWrapped */
+               {errno = EINVAL; return -1;}
+#endif /* ndef MustBeWrapped */
+       if (x == Mono_Posix_SockaddrType_Sockaddr)
+#ifdef Sockaddr
+               {*r = Sockaddr; return 0;}
+#else /* def Sockaddr */
+               {errno = EINVAL; return -1;}
+#endif /* ndef Sockaddr */
+       if (x == Mono_Posix_SockaddrType_SockaddrIn)
+#ifdef SockaddrIn
+               {*r = SockaddrIn; return 0;}
+#else /* def SockaddrIn */
+               {errno = EINVAL; return -1;}
+#endif /* ndef SockaddrIn */
+       if (x == Mono_Posix_SockaddrType_SockaddrIn6)
+#ifdef SockaddrIn6
+               {*r = SockaddrIn6; return 0;}
+#else /* def SockaddrIn6 */
+               {errno = EINVAL; return -1;}
+#endif /* ndef SockaddrIn6 */
+       if (x == Mono_Posix_SockaddrType_SockaddrStorage)
+#ifdef SockaddrStorage
+               {*r = SockaddrStorage; return 0;}
+#else /* def SockaddrStorage */
+               {errno = EINVAL; return -1;}
+#endif /* ndef SockaddrStorage */
+       if (x == Mono_Posix_SockaddrType_SockaddrUn)
+#ifdef SockaddrUn
+               {*r = SockaddrUn; return 0;}
+#else /* def SockaddrUn */
+               {errno = EINVAL; return -1;}
+#endif /* ndef SockaddrUn */
+       if (x == 0)
+               return 0;
+       errno = EINVAL; return -1;
+}
+
+int Mono_Posix_ToSockaddrType (int x, int *r)
+{
+       *r = 0;
+       if (x == 0)
+               return 0;
+#ifdef Invalid
+       if (x == Invalid)
+               {*r = Mono_Posix_SockaddrType_Invalid; return 0;}
+#endif /* ndef Invalid */
+#ifdef MustBeWrapped
+       if (x == MustBeWrapped)
+               {*r = Mono_Posix_SockaddrType_MustBeWrapped; return 0;}
+#endif /* ndef MustBeWrapped */
+#ifdef Sockaddr
+       if (x == Sockaddr)
+               {*r = Mono_Posix_SockaddrType_Sockaddr; return 0;}
+#endif /* ndef Sockaddr */
+#ifdef SockaddrIn
+       if (x == SockaddrIn)
+               {*r = Mono_Posix_SockaddrType_SockaddrIn; return 0;}
+#endif /* ndef SockaddrIn */
+#ifdef SockaddrIn6
+       if (x == SockaddrIn6)
+               {*r = Mono_Posix_SockaddrType_SockaddrIn6; return 0;}
+#endif /* ndef SockaddrIn6 */
+#ifdef SockaddrStorage
+       if (x == SockaddrStorage)
+               {*r = Mono_Posix_SockaddrType_SockaddrStorage; return 0;}
+#endif /* ndef SockaddrStorage */
+#ifdef SockaddrUn
+       if (x == SockaddrUn)
+               {*r = Mono_Posix_SockaddrType_SockaddrUn; return 0;}
+#endif /* ndef SockaddrUn */
+       errno = EINVAL; return -1;
+}
+
 int Mono_Posix_FromSysconfName (int x, int *r)
 {
        *r = 0;
@@ -7902,6 +8068,12 @@ int Mono_Posix_FromUnixAddressFamily (int x, int *r)
 #else /* def AF_X25 */
                {errno = EINVAL; return -1;}
 #endif /* ndef AF_X25 */
+       if (x == Mono_Posix_UnixAddressFamily_Unknown)
+#ifdef Unknown
+               {*r = Unknown; return 0;}
+#else /* def Unknown */
+               {errno = EINVAL; return -1;}
+#endif /* ndef Unknown */
        if (x == 0)
                return 0;
        errno = EINVAL; return -1;
@@ -8068,6 +8240,10 @@ int Mono_Posix_ToUnixAddressFamily (int x, int *r)
        if (x == AF_X25)
                {*r = Mono_Posix_UnixAddressFamily_AF_X25; return 0;}
 #endif /* ndef AF_X25 */
+#ifdef Unknown
+       if (x == Unknown)
+               {*r = Mono_Posix_UnixAddressFamily_Unknown; return 0;}
+#endif /* ndef Unknown */
        errno = EINVAL; return -1;
 }
 
index 34cdb68ab4da8bab5ff81cddbf5c53e4e976b712..eb5bff9ec9aefc5fcc786f2cac5b47410317a208 100644 (file)
@@ -1018,6 +1018,25 @@ enum Mono_Posix_Signum {
 int Mono_Posix_FromSignum (int x, int *r);
 int Mono_Posix_ToSignum (int x, int *r);
 
+enum Mono_Posix_SockaddrType {
+       Mono_Posix_SockaddrType_Invalid               = 0x00000000,
+       #define Mono_Posix_SockaddrType_Invalid         Mono_Posix_SockaddrType_Invalid
+       Mono_Posix_SockaddrType_MustBeWrapped         = 0x00008000,
+       #define Mono_Posix_SockaddrType_MustBeWrapped   Mono_Posix_SockaddrType_MustBeWrapped
+       Mono_Posix_SockaddrType_Sockaddr              = 0x00000003,
+       #define Mono_Posix_SockaddrType_Sockaddr        Mono_Posix_SockaddrType_Sockaddr
+       Mono_Posix_SockaddrType_SockaddrIn            = 0x00000004,
+       #define Mono_Posix_SockaddrType_SockaddrIn      Mono_Posix_SockaddrType_SockaddrIn
+       Mono_Posix_SockaddrType_SockaddrIn6           = 0x00000005,
+       #define Mono_Posix_SockaddrType_SockaddrIn6     Mono_Posix_SockaddrType_SockaddrIn6
+       Mono_Posix_SockaddrType_SockaddrStorage       = 0x00000001,
+       #define Mono_Posix_SockaddrType_SockaddrStorage Mono_Posix_SockaddrType_SockaddrStorage
+       Mono_Posix_SockaddrType_SockaddrUn            = 0x00000002,
+       #define Mono_Posix_SockaddrType_SockaddrUn      Mono_Posix_SockaddrType_SockaddrUn
+};
+int Mono_Posix_FromSockaddrType (int x, int *r);
+int Mono_Posix_ToSockaddrType (int x, int *r);
+
 enum Mono_Posix_SysconfName {
        Mono_Posix_SysconfName__SC_2_CHAR_TERM                        = 0x0000005f,
        #define Mono_Posix_SysconfName__SC_2_CHAR_TERM                  Mono_Posix_SysconfName__SC_2_CHAR_TERM
@@ -1587,6 +1606,8 @@ enum Mono_Posix_UnixAddressFamily {
        #define Mono_Posix_UnixAddressFamily_AF_WANPIPE    Mono_Posix_UnixAddressFamily_AF_WANPIPE
        Mono_Posix_UnixAddressFamily_AF_X25              = 0x00000009,
        #define Mono_Posix_UnixAddressFamily_AF_X25        Mono_Posix_UnixAddressFamily_AF_X25
+       Mono_Posix_UnixAddressFamily_Unknown             = 0x00010000,
+       #define Mono_Posix_UnixAddressFamily_Unknown       Mono_Posix_UnixAddressFamily_Unknown
 };
 int Mono_Posix_FromUnixAddressFamily (int x, int *r);
 int Mono_Posix_ToUnixAddressFamily (int x, int *r);
@@ -1799,9 +1820,13 @@ int Mono_Posix_ToXattrFlags (int x, int *r);
  */
 
 struct Mono_Posix_Flock;
+struct Mono_Posix_In6Addr;
+struct Mono_Posix_InAddr;
 struct Mono_Posix_Iovec;
 struct Mono_Posix_Linger;
 struct Mono_Posix_Pollfd;
+struct Mono_Posix_SockaddrIn;
+struct Mono_Posix_SockaddrIn6;
 struct Mono_Posix_Stat;
 struct Mono_Posix_Statvfs;
 struct Mono_Posix_Syscall__Dirent;
@@ -1813,6 +1838,8 @@ struct Mono_Posix_Timespec;
 struct Mono_Posix_Timeval;
 struct Mono_Posix_Timezone;
 struct Mono_Posix_Utimbuf;
+struct Mono_Posix__SockaddrDynamic;
+struct Mono_Posix__SockaddrHeader;
 struct Mono_Unix_UnixSignal_SignalInfo;
 
 /*
@@ -1823,6 +1850,8 @@ struct flock;
 struct iovec;
 struct linger;
 struct pollfd;
+struct sockaddr_in;
+struct sockaddr_in6;
 struct timespec;
 struct timeval;
 struct timezone;
@@ -1852,6 +1881,15 @@ int
 Mono_Posix_ToFlock (struct flock *from, struct Mono_Posix_Flock* to);
 
 
+struct Mono_Posix_In6Addr {
+       guint64 addr0;
+       guint64 addr1;
+};
+
+struct Mono_Posix_InAddr {
+       unsigned int s_addr;
+};
+
 struct Mono_Posix_Iovec {
        void*   iov_base;
        guint64 iov_len;
@@ -1886,6 +1924,34 @@ int
 Mono_Posix_ToPollfd (struct pollfd *from, struct Mono_Posix_Pollfd* to);
 
 
+struct Mono_Posix_SockaddrIn {
+       int                      type;
+       int                      _sa_family;
+       unsigned short           sin_port;
+       struct Mono_Posix_InAddr sin_addr;
+};
+
+int
+Mono_Posix_FromSockaddrIn (struct Mono_Posix_SockaddrIn* from, struct sockaddr_in *to);
+int
+Mono_Posix_ToSockaddrIn (struct sockaddr_in *from, struct Mono_Posix_SockaddrIn* to);
+
+
+struct Mono_Posix_SockaddrIn6 {
+       int                       type;
+       int                       _sa_family;
+       unsigned short            sin6_port;
+       unsigned int              sin6_flowinfo;
+       struct Mono_Posix_In6Addr sin6_addr;
+       unsigned int              sin6_scope_id;
+};
+
+int
+Mono_Posix_FromSockaddrIn6 (struct Mono_Posix_SockaddrIn6* from, struct sockaddr_in6 *to);
+int
+Mono_Posix_ToSockaddrIn6 (struct sockaddr_in6 *from, struct Mono_Posix_SockaddrIn6* to);
+
+
 struct Mono_Posix_Stat {
        guint64      st_dev;         /* dev_t     */
        guint64      st_ino;         /* ino_t     */
@@ -2013,6 +2079,18 @@ int
 Mono_Posix_ToUtimbuf (struct utimbuf *from, struct Mono_Posix_Utimbuf* to);
 
 
+struct Mono_Posix__SockaddrDynamic {
+       int            type;
+       int            sa_family;
+       unsigned char* data;
+       gint64         len;
+};
+
+struct Mono_Posix__SockaddrHeader {
+       int type;
+       int sa_family;
+};
+
 struct Mono_Unix_UnixSignal_SignalInfo {
        int   signum;
        int   count;
@@ -2035,14 +2113,17 @@ 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_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);
+int Mono_Posix_FromSockaddr (struct Mono_Posix__SockaddrHeader* source, void* destination);
 int Mono_Posix_FromStat (struct Mono_Posix_Stat* source, void* destination);
 int Mono_Posix_FromStatvfs (struct Mono_Posix_Statvfs* source, void* destination);
 int Mono_Posix_SIGRTMAX (void);
 int Mono_Posix_SIGRTMIN (void);
-int Mono_Posix_Stdlib__IOFBF (void);
-int Mono_Posix_Stdlib__IOLBF (void);
-int Mono_Posix_Stdlib__IONBF (void);
+int Mono_Posix_SockaddrStorage_get_size (void);
+int Mono_Posix_SockaddrUn_get_sizeof_sun_path (void);
+int Mono_Posix_Sockaddr_GetNativeSize (struct Mono_Posix__SockaddrHeader* address, gint64* size);
 int Mono_Posix_Stdlib_BUFSIZ (void);
 void* Mono_Posix_Stdlib_calloc (guint64 nmemb, guint64 size);
 int Mono_Posix_Stdlib_clearerr (void* stream);
@@ -2078,8 +2159,15 @@ void* Mono_Posix_Stdlib_stdin (void);
 void* Mono_Posix_Stdlib_stdout (void);
 guint64 Mono_Posix_Stdlib_strlen (void* s);
 int Mono_Posix_Stdlib_TMP_MAX (void);
+int Mono_Posix_Stdlib__IOFBF (void);
+int Mono_Posix_Stdlib__IOLBF (void);
+int Mono_Posix_Stdlib__IONBF (void);
+int Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* address);
+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_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);
 int Mono_Posix_Syscall_endfsent (void);
 int Mono_Posix_Syscall_endgrent (void);
@@ -2103,9 +2191,6 @@ int Mono_Posix_Syscall_fstatvfs (int fd, struct Mono_Posix_Statvfs* buf);
 int Mono_Posix_Syscall_ftruncate (int fd, gint64 length);
 int Mono_Posix_Syscall_futimens (int fd, struct Mono_Posix_Timespec* times);
 int Mono_Posix_Syscall_futimes (int fd, struct Mono_Posix_Timeval* tvp);
-int Mono_Posix_Syscall_get_at_fdcwd (void);
-gint64 Mono_Posix_Syscall_get_utime_now (void);
-gint64 Mono_Posix_Syscall_get_utime_omit (void);
 void* Mono_Posix_Syscall_getcwd (char* buf, guint64 size);
 int Mono_Posix_Syscall_getdomainname (char* name, guint64 len);
 int Mono_Posix_Syscall_getfsent (struct Mono_Posix_Syscall__Fstab* fs);
@@ -2119,18 +2204,21 @@ int Mono_Posix_Syscall_getgrnam_r (const char* name, struct Mono_Posix_Syscall__
 gint64 Mono_Posix_Syscall_gethostid (void);
 int Mono_Posix_Syscall_gethostname (char* name, guint64 len);
 int Mono_Posix_Syscall_getlogin_r (char* name, guint64 bufsize);
+int Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address);
 int Mono_Posix_Syscall_getpwent (struct Mono_Posix_Syscall__Passwd* pwbuf);
 int Mono_Posix_Syscall_getpwnam (const char* name, struct Mono_Posix_Syscall__Passwd* passwd);
 int Mono_Posix_Syscall_getpwnam_r (const char* name, struct Mono_Posix_Syscall__Passwd* pwbuf, void** pwbufp);
 int Mono_Posix_Syscall_getpwuid (unsigned int uid, struct Mono_Posix_Syscall__Passwd* passwd);
 int Mono_Posix_Syscall_getpwuid_r (unsigned int uid, struct Mono_Posix_Syscall__Passwd* pwbuf, void** pwbufp);
+int Mono_Posix_Syscall_getsockname (int socket, struct Mono_Posix__SockaddrHeader* address);
 int Mono_Posix_Syscall_getsockopt (int socket, int level, int option_name, void* option_value, gint64* option_len);
 int Mono_Posix_Syscall_getsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value);
 int Mono_Posix_Syscall_getsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value);
 int Mono_Posix_Syscall_gettimeofday (struct Mono_Posix_Timeval* tv, void* ignore);
 gint64 Mono_Posix_Syscall_getxattr (const char* path, const char* name, unsigned char* value, guint64 size);
-int Mono_Posix_Syscall_L_ctermid (void);
-int Mono_Posix_Syscall_L_cuserid (void);
+int Mono_Posix_Syscall_get_at_fdcwd (void);
+gint64 Mono_Posix_Syscall_get_utime_now (void);
+gint64 Mono_Posix_Syscall_get_utime_omit (void);
 gint64 Mono_Posix_Syscall_lgetxattr (const char* path, const char* name, unsigned char* value, guint64 size);
 gint64 Mono_Posix_Syscall_listxattr (const char* path, unsigned char* list, guint64 size);
 gint64 Mono_Posix_Syscall_llistxattr (const char* path, unsigned char* list, guint64 size);
@@ -2140,6 +2228,8 @@ gint64 Mono_Posix_Syscall_lseek (int fd, gint64 offset, int whence);
 int Mono_Posix_Syscall_lsetxattr (const char* path, const char* name, unsigned char* value, guint64 size, int flags);
 int Mono_Posix_Syscall_lstat (const char* file_name, struct Mono_Posix_Stat* buf);
 int Mono_Posix_Syscall_lutimes (const char* filename, struct Mono_Posix_Timeval* tvp);
+int Mono_Posix_Syscall_L_ctermid (void);
+int Mono_Posix_Syscall_L_cuserid (void);
 int Mono_Posix_Syscall_mincore (void* start, guint64 length, unsigned char* vec);
 int Mono_Posix_Syscall_mknod (const char* pathname, unsigned int mode, guint64 dev);
 int Mono_Posix_Syscall_mknodat (int dirfd, const char* pathname, unsigned int mode, guint64 dev);
@@ -2152,8 +2242,8 @@ int Mono_Posix_Syscall_munlock (void* start, guint64 len);
 int Mono_Posix_Syscall_munmap (void* start, guint64 length);
 int Mono_Posix_Syscall_nanosleep (struct Mono_Posix_Timespec* req, struct Mono_Posix_Timespec* rem);
 int Mono_Posix_Syscall_open (const char* pathname, int flags);
-int Mono_Posix_Syscall_open_mode (const char* pathname, int flags, unsigned int mode);
 int Mono_Posix_Syscall_openlog (void* ident, int option, int facility);
+int Mono_Posix_Syscall_open_mode (const char* pathname, int flags, unsigned int mode);
 gint64 Mono_Posix_Syscall_pathconf (const char* path, int name, int defaultError);
 int Mono_Posix_Syscall_pipe (int* reading, int* writing);
 int Mono_Posix_Syscall_posix_fadvise (int fd, gint64 offset, gint64 len, int advice);
@@ -2171,12 +2261,14 @@ gint64 Mono_Posix_Syscall_readlink (const char* path, unsigned char* buf, guint6
 gint64 Mono_Posix_Syscall_readlinkat (int dirfd, const char* pathname, unsigned char* buf, guint64 bufsiz);
 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);
 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_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);
 int Mono_Posix_Syscall_setgrent (void);
@@ -2215,6 +2307,9 @@ gint64 Mono_Posix_Syscall_write (int fd, void* buf, guint64 count);
 gint64 Mono_Posix_Syscall_writev (int fd, struct Mono_Posix_Iovec* iov, int iovcnt);
 int Mono_Posix_Syscall_WSTOPSIG (int status);
 int Mono_Posix_Syscall_WTERMSIG (int status);
+int Mono_Posix_ToIn6Addr (void* source, struct Mono_Posix_In6Addr* destination);
+int Mono_Posix_ToInAddr (void* source, struct Mono_Posix_InAddr* destination);
+int Mono_Posix_ToSockaddr (void* source, gint64 size, struct Mono_Posix__SockaddrHeader* destination);
 int Mono_Posix_ToStat (void* source, struct Mono_Posix_Stat* destination);
 int Mono_Posix_ToStatvfs (void* source, struct Mono_Posix_Statvfs* destination);
 void* Mono_Unix_UnixSignal_install (int signum);
index 188df56a18e25e6c978b73f8a4044a4fdaaddbc3..5bfdabf46f15b7bb5395b1c2472d82aad9646913 100644 (file)
@@ -11,6 +11,7 @@
 #include <sys/time.h>
 #include <netinet/in.h>
 #include <sys/un.h>
+#include <unistd.h>
 
 #include <stddef.h>
 
 
 G_BEGIN_DECLS
 
+int
+Mono_Posix_SockaddrStorage_get_size (void)
+{
+       return sizeof (struct sockaddr_storage);
+}
+
+int
+Mono_Posix_SockaddrUn_get_sizeof_sun_path (void)
+{
+       struct sockaddr_un sun;
+       return sizeof (sun.sun_path);
+}
+
+int
+Mono_Posix_FromInAddr (struct Mono_Posix_InAddr* source, void* destination)
+{
+       memcpy (&((struct in_addr*)destination)->s_addr, &source->s_addr, 4);
+       return 0;
+}
+
+int
+Mono_Posix_ToInAddr (void* source, struct Mono_Posix_InAddr* destination)
+{
+       memcpy (&destination->s_addr, &((struct in_addr*)source)->s_addr, 4);
+       return 0;
+}
+
+int
+Mono_Posix_FromIn6Addr (struct Mono_Posix_In6Addr* source, void* destination)
+{
+       memcpy (&((struct in6_addr*)destination)->s6_addr, &source->addr0, 16);
+       return 0;
+}
+
+int
+Mono_Posix_ToIn6Addr (void* source, struct Mono_Posix_In6Addr* destination)
+{
+       memcpy (&destination->addr0, &((struct in6_addr*)source)->s6_addr, 16);
+       return 0;
+}
+
+
 int
 Mono_Posix_Syscall_socketpair (int domain, int type, int protocol, int* socket1, int* socket2)
 {
@@ -123,6 +166,290 @@ Mono_Posix_Syscall_setsockopt_linger (int socket, int level, int option_name, st
        return setsockopt (socket, level, option_name, &ling, sizeof (struct linger));
 }
 
+static int
+get_addrlen (struct Mono_Posix__SockaddrHeader* address, socklen_t* addrlen)
+{
+       if (!address) {
+               *addrlen = 0;
+               return 0;
+       }
+
+       switch (address->type) {
+       case Mono_Posix_SockaddrType_SockaddrStorage:
+               mph_return_if_socklen_t_overflow (((struct Mono_Posix__SockaddrDynamic*) address)->len);
+               *addrlen = ((struct Mono_Posix__SockaddrDynamic*) address)->len;
+               return 0;
+       case Mono_Posix_SockaddrType_SockaddrUn:
+               mph_return_if_socklen_t_overflow (offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len);
+               *addrlen = offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len;
+               return 0;
+       case Mono_Posix_SockaddrType_Sockaddr: *addrlen = sizeof (struct sockaddr); return 0;
+       case Mono_Posix_SockaddrType_SockaddrIn: *addrlen = sizeof (struct sockaddr_in); return 0;
+       case Mono_Posix_SockaddrType_SockaddrIn6: *addrlen = sizeof (struct sockaddr_in6); return 0;
+       default:
+               *addrlen = 0;
+               errno = EINVAL;
+               return -1;
+       }
+}
+
+int
+Mono_Posix_Sockaddr_GetNativeSize (struct Mono_Posix__SockaddrHeader* address, gint64* size)
+{
+       socklen_t value;
+       int r;
+
+       r = get_addrlen (address, &value);
+       *size = value;
+       return r;
+}
+
+int
+Mono_Posix_FromSockaddr (struct Mono_Posix__SockaddrHeader* source, void* destination)
+{
+       if (!source)
+               return 0;
+
+       switch (source->type) {
+       case Mono_Posix_SockaddrType_SockaddrStorage:
+               // Do nothing, don't copy source->sa_family into addr->sa_family
+               return 0;
+
+       case Mono_Posix_SockaddrType_SockaddrUn:
+               memcpy (((struct sockaddr_un*) destination)->sun_path, ((struct Mono_Posix__SockaddrDynamic*) source)->data, ((struct Mono_Posix__SockaddrDynamic*) source)->len);
+               break;
+
+       case Mono_Posix_SockaddrType_Sockaddr:
+               break;
+
+       case Mono_Posix_SockaddrType_SockaddrIn:
+               if (Mono_Posix_FromSockaddrIn ((struct Mono_Posix_SockaddrIn*) source, (struct sockaddr_in*) destination) != 0)
+                       return -1;
+               break;
+
+       case Mono_Posix_SockaddrType_SockaddrIn6:
+               if (Mono_Posix_FromSockaddrIn6 ((struct Mono_Posix_SockaddrIn6*) source, (struct sockaddr_in6*) destination) != 0)
+                       return -1;
+               break;
+
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+
+       int family;
+       if (Mono_Posix_FromUnixAddressFamily (source->sa_family, &family) != 0)
+               return -1;
+       ((struct sockaddr*) destination)->sa_family = family;
+
+       return 0;
+}
+
+int
+Mono_Posix_ToSockaddr (void* source, gint64 size, struct Mono_Posix__SockaddrHeader* destination)
+{
+       struct Mono_Posix__SockaddrDynamic* destination_dyn;
+
+       if (!destination)
+               return 0;
+
+       switch (destination->type) {
+       case Mono_Posix_SockaddrType_Sockaddr:
+               if (size < offsetof (struct sockaddr, sa_family) + sizeof (sa_family_t)) {
+                       errno = ENOBUFS;
+                       return -1;
+               }
+               break;
+
+       case Mono_Posix_SockaddrType_SockaddrStorage:
+               destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
+               if (size > destination_dyn->len) {
+                       errno = ENOBUFS;
+                       return -1;
+               }
+               destination_dyn->len = size;
+               break;
+
+       case Mono_Posix_SockaddrType_SockaddrUn:
+               destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
+               if (size - offsetof (struct sockaddr_un, sun_path) > destination_dyn->len) {
+                       errno = ENOBUFS;
+                       return -1;
+               }
+               destination_dyn->len = size - offsetof (struct sockaddr_un, sun_path);
+               memcpy (destination_dyn->data, ((struct sockaddr_un*) source)->sun_path, size);
+               break;
+
+       case Mono_Posix_SockaddrType_SockaddrIn:
+               if (size != sizeof (struct sockaddr_in)) {
+                       errno = ENOBUFS;
+                       return -1;
+               }
+               if (Mono_Posix_ToSockaddrIn ((struct sockaddr_in*) source, (struct Mono_Posix_SockaddrIn*) destination) != 0)
+                       return -1;
+               break;
+
+       case Mono_Posix_SockaddrType_SockaddrIn6:
+               if (size != sizeof (struct sockaddr_in6)) {
+                       errno = ENOBUFS;
+                       return -1;
+               }
+               if (Mono_Posix_ToSockaddrIn6 ((struct sockaddr_in6*) source, (struct Mono_Posix_SockaddrIn6*) destination) != 0)
+                       return -1;
+               break;
+
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (Mono_Posix_ToUnixAddressFamily (((struct sockaddr*) source)->sa_family, &destination->sa_family) != 0)
+               destination->sa_family = Mono_Posix_UnixAddressFamily_Unknown;
+
+       return 0;
+}
+
+// Macro for allocating space for the native sockaddr_* structure
+// Must be a macro because it is using alloca()
+
+#define ALLOC_SOCKADDR                                                  \
+    socklen_t addrlen;                                                  \
+    struct sockaddr* addr;                                              \
+    gboolean need_free = 0;                                             \
+                                                                        \
+    if (get_addrlen (address, &addrlen) != 0)                           \
+        return -1;                                                      \
+    if (address == NULL) {                                              \
+        addr = NULL;                                                    \
+    } else if (address->type == Mono_Posix_SockaddrType_SockaddrStorage) { \
+        addr = (struct sockaddr*) ((struct Mono_Posix__SockaddrDynamic*) address)->data; \
+    } else if (address->type == Mono_Posix_SockaddrType_SockaddrUn) { \
+        /* Use alloca() for up to 2048 bytes, use malloc() otherwise */ \
+        need_free = addrlen > 2048;                                     \
+        addr = need_free ? malloc (addrlen) : alloca (addrlen);         \
+        if (!addr)                                                      \
+            return -1;                                                  \
+    } else {                                                            \
+        addr = alloca (addrlen);                                        \
+    }
+
+
+int
+Mono_Posix_Syscall_bind (int socket, struct Mono_Posix__SockaddrHeader* address)
+{
+       int r;
+
+       ALLOC_SOCKADDR
+       if (Mono_Posix_FromSockaddr (address, addr) != 0) {
+               if (need_free)
+                       free (addr);
+               return -1;
+       }
+
+       r = bind (socket, addr, addrlen);
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
+int
+Mono_Posix_Syscall_connect (int socket, struct Mono_Posix__SockaddrHeader* address)
+{
+       int r;
+
+       ALLOC_SOCKADDR
+       if (Mono_Posix_FromSockaddr (address, addr) != 0) {
+               if (need_free)
+                       free (addr);
+               return -1;
+       }
+
+       r = connect (socket, addr, addrlen);
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
+int
+Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* address)
+{
+       int r;
+
+       ALLOC_SOCKADDR
+
+       r = accept (socket, addr, &addrlen);
+
+       if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
+               close (r);
+               r = -1;
+       }
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
+int
+Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* address, int flags)
+{
+       int r;
+
+       ALLOC_SOCKADDR
+
+       r = accept4 (socket, addr, &addrlen, flags);
+
+       if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
+               close (r);
+               r = -1;
+       }
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
+int
+Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address)
+{
+       int r;
+
+       ALLOC_SOCKADDR
+
+       r = getpeername (socket, addr, &addrlen);
+
+       if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
+               r = -1;
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
+int
+Mono_Posix_Syscall_getsockname (int socket, struct Mono_Posix__SockaddrHeader* address)
+{
+       int r;
+
+       ALLOC_SOCKADDR
+
+       r = getsockname (socket, addr, &addrlen);
+
+       if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
+               r = -1;
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
 gint64
 Mono_Posix_Syscall_recv (int socket, void* message, guint64 length, int flags)
 {
@@ -138,3 +465,52 @@ Mono_Posix_Syscall_send (int socket, void* message, guint64 length, int flags)
 
        return send (socket, message, length, flags);
 }
+
+gint64
+Mono_Posix_Syscall_recvfrom (int socket, void* buffer, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
+{
+       int r;
+
+       mph_return_if_size_t_overflow (length);
+
+       ALLOC_SOCKADDR
+
+       r = recvfrom (socket, buffer, length, flags, addr, &addrlen);
+
+       if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
+               r = -1;
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
+gint64
+Mono_Posix_Syscall_sendto (int socket, void* message, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
+{
+       int r;
+
+       mph_return_if_size_t_overflow (length);
+
+       ALLOC_SOCKADDR
+       if (Mono_Posix_FromSockaddr (address, addr) != 0) {
+               if (need_free)
+                       free (addr);
+               return -1;
+       }
+
+       r = sendto (socket, message, length, flags, addr, addrlen);
+
+       if (need_free)
+               free (addr);
+
+       return r;
+}
+
+// vim: noexpandtab
+// Local Variables: 
+// tab-width: 4
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// End: