[#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>
# 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)
{
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:
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);
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]
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
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
}
}
+ // 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.
}
#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>
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
}
}
// vim: noexpandtab
+// Local Variables:
+// tab-width: 4
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// End:
}
[Test]
- public void Socket ()
+ public void TestSocket ()
{
int socket;
if ((socket = Syscall.socket (UnixAddressFamily.AF_UNIX, UnixSocketType.SOCK_STREAM, 0)) < 0)
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]);
+ });
+ }
}
}
--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:
/*
- * 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.
*/
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;
#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;
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;
}
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
#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);
*/
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;
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;
/*
struct iovec;
struct linger;
struct pollfd;
+struct sockaddr_in;
+struct sockaddr_in6;
struct timespec;
struct timeval;
struct timezone;
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;
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 */
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;
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);
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);
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);
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);
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);
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);
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);
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);
#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)
{
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)
{
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: