[Mono.Posix] Add wrappers for struct sockaddr_*
[mono.git] / mcs / class / Mono.Posix / Mono.Unix.Native / Syscall.cs
index 5685761071544a5a1c10ede10f5ed6f030b87e78..74af55b2fd6c2eccc24007858195507f240b0fb4 100644 (file)
@@ -149,7 +149,19 @@ namespace Mono.Unix.Native {
                O_DIRECTORY = 0x00010000,
                O_DIRECT    = 0x00004000,
                O_ASYNC     = 0x00002000,
-               O_LARGEFILE = 0x00008000
+               O_LARGEFILE = 0x00008000,
+               O_CLOEXEC   = 0x00080000,
+               O_PATH      = 0x00200000
+       }
+       
+       [Map][Flags]
+       [CLSCompliant (false)]
+       public enum AtFlags : int {
+               AT_SYMLINK_NOFOLLOW = 0x00000100,
+               AT_REMOVEDIR        = 0x00000200,
+               AT_SYMLINK_FOLLOW   = 0x00000400,
+               AT_NO_AUTOMOUNT     = 0x00000800,
+               AT_EMPTY_PATH       = 0x00001000
        }
        
        // mode_t
@@ -211,6 +223,7 @@ namespace Mono.Unix.Native {
                F_GETOWN   =    9, // Get owner of socket (receiver of SIGIO).
                F_SETSIG   =   10, // Set number of signal to be sent.
                F_GETSIG   =   11, // Get number of signal to be sent.
+               F_NOCACHE  =   48, // OSX: turn data caching off/on for this fd.
                F_SETLEASE = 1024, // Set a lease.
                F_GETLEASE = 1025, // Enquire what lease is active.
                F_NOTIFY   = 1026, // Required notifications on a directory
@@ -714,15 +727,210 @@ namespace Mono.Unix.Native {
                MREMAP_MAYMOVE = 0x1,
        }
 
+       [Map]
+       [CLSCompliant (false)]
+       public enum UnixSocketType : int {
+               SOCK_STREAM    =  1, // Byte-stream socket
+               SOCK_DGRAM     =  2, // Datagram socket
+               SOCK_RAW       =  3, // Raw protocol interface (linux specific)
+               SOCK_RDM       =  4, // Reliably-delivered messages (linux specific)
+               SOCK_SEQPACKET =  5, // Sequenced-packet socket
+               SOCK_DCCP      =  6, // Datagram Congestion Control Protocol (linux specific)
+               SOCK_PACKET    = 10, // Linux specific
+       }
+
+       [Map][Flags]
+       [CLSCompliant (false)]
+       public enum UnixSocketFlags : int {
+               SOCK_CLOEXEC  = 0x80000, /* Atomically set close-on-exec flag for the new descriptor(s). */
+               SOCK_NONBLOCK = 0x00800, /* Atomically mark descriptor(s) as non-blocking. */
+       }
+
+       [Map]
+       [CLSCompliant (false)]
+       public enum UnixSocketProtocol : int {
+               IPPROTO_ICMP    =    1, /* Internet Control Message Protocol */
+               IPPROTO_IGMP    =    2, /* Internet Group Management Protocol */
+               IPPROTO_IPIP    =    4, /* IPIP tunnels (older KA9Q tunnels use 94) */
+               IPPROTO_TCP     =    6, /* Transmission Control Protocol */
+               IPPROTO_EGP     =    8, /* Exterior Gateway Protocol */
+               IPPROTO_PUP     =   12, /* PUP protocol */
+               IPPROTO_UDP     =   17, /* User Datagram Protocol */
+               IPPROTO_IDP     =   22, /* XNS IDP protocol */
+               IPPROTO_TP      =   29, /* SO Transport Protocol Class 4 */
+               IPPROTO_DCCP    =   33, /* Datagram Congestion Control Protocol */
+               IPPROTO_IPV6    =   41, /* IPv6-in-IPv4 tunnelling */
+               IPPROTO_RSVP    =   46, /* RSVP Protocol */
+               IPPROTO_GRE     =   47, /* Cisco GRE tunnels (rfc 1701,1702) */
+               IPPROTO_ESP     =   50, /* Encapsulation Security Payload protocol */
+               IPPROTO_AH      =   51, /* Authentication Header protocol */
+               IPPROTO_MTP     =   92, /* Multicast Transport Protocol */
+               IPPROTO_BEETPH  =   94, /* IP option pseudo header for BEET */
+               IPPROTO_ENCAP   =   98, /* Encapsulation Header */
+               IPPROTO_PIM     =  103, /* Protocol Independent Multicast */
+               IPPROTO_COMP    =  108, /* Compression Header Protocol */
+               IPPROTO_SCTP    =  132, /* Stream Control Transport Protocol */
+               IPPROTO_UDPLITE =  136, /* UDP-Lite (RFC 3828) */
+               IPPROTO_RAW     =  255, /* Raw IP packets */
+
+               // Number used by linux (0) has a special meaning for socket()
+               IPPROTO_IP      = 1024, /* Dummy protocol for TCP */
+               // Number used by linux (1) clashes with IPPROTO_ICMP
+               SOL_SOCKET      = 2048, /* For setsockopt() / getsockopt(): Options to be accessed at socket level, not protocol level. */
+       }
+
+       [Map]
+       [CLSCompliant (false)]
+       public enum UnixAddressFamily : int {
+               AF_UNSPEC     =  0,  /* Unspecified. */
+               AF_UNIX       =  1,  /* Local to host (pipes and file-domain). */
+               AF_INET       =  2,  /* IP protocol family. */
+               AF_AX25       =  3,  /* Amateur Radio AX.25. */
+               AF_IPX        =  4,  /* Novell Internet Protocol. */
+               AF_APPLETALK  =  5,  /* Appletalk DDP. */
+               AF_NETROM     =  6,  /* Amateur radio NetROM. */
+               AF_BRIDGE     =  7,  /* Multiprotocol bridge. */
+               AF_ATMPVC     =  8,  /* ATM PVCs. */
+               AF_X25        =  9,  /* Reserved for X.25 project. */
+               AF_INET6      = 10,  /* IP version 6. */
+               AF_ROSE       = 11,  /* Amateur Radio X.25 PLP. */
+               AF_DECnet     = 12,  /* Reserved for DECnet project. */
+               AF_NETBEUI    = 13,  /* Reserved for 802.2LLC project. */
+               AF_SECURITY   = 14,  /* Security callback pseudo AF. */
+               AF_KEY        = 15,  /* PF_KEY key management API. */
+               AF_NETLINK    = 16,
+               AF_PACKET     = 17,  /* Packet family. */
+               AF_ASH        = 18,  /* Ash. */
+               AF_ECONET     = 19,  /* Acorn Econet. */
+               AF_ATMSVC     = 20,  /* ATM SVCs. */
+               AF_RDS        = 21,  /* RDS sockets. */
+               AF_SNA        = 22,  /* Linux SNA Project */
+               AF_IRDA       = 23,  /* IRDA sockets. */
+               AF_PPPOX      = 24,  /* PPPoX sockets. */
+               AF_WANPIPE    = 25,  /* Wanpipe API sockets. */
+               AF_LLC        = 26,  /* Linux LLC. */
+               AF_CAN        = 29,  /* Controller Area Network. */
+               AF_TIPC       = 30,  /* TIPC sockets. */
+               AF_BLUETOOTH  = 31,  /* Bluetooth sockets. */
+               AF_IUCV       = 32,  /* IUCV sockets. */
+               AF_RXRPC      = 33,  /* RxRPC sockets. */
+               AF_ISDN       = 34,  /* mISDN sockets. */
+               AF_PHONET     = 35,  /* Phonet sockets. */
+               AF_IEEE802154 = 36,  /* IEEE 802.15.4 sockets. */
+               AF_CAIF       = 37,  /* CAIF sockets. */
+               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]
+       [CLSCompliant (false)]
+       public enum UnixSocketOptionName : int {
+               SO_DEBUG                         =  1,
+               SO_REUSEADDR                     =  2,
+               SO_TYPE                          =  3,
+               SO_ERROR                         =  4,
+               SO_DONTROUTE                     =  5,
+               SO_BROADCAST                     =  6,
+               SO_SNDBUF                        =  7,
+               SO_RCVBUF                        =  8,
+               SO_SNDBUFFORCE                   = 32,
+               SO_RCVBUFFORCE                   = 33,
+               SO_KEEPALIVE                     =  9,
+               SO_OOBINLINE                     = 10,
+               SO_NO_CHECK                      = 11,
+               SO_PRIORITY                      = 12,
+               SO_LINGER                        = 13,
+               SO_BSDCOMPAT                     = 14,
+               SO_REUSEPORT                     = 15,
+               SO_PASSCRED                      = 16,
+               SO_PEERCRED                      = 17,
+               SO_RCVLOWAT                      = 18,
+               SO_SNDLOWAT                      = 19,
+               SO_RCVTIMEO                      = 20,
+               SO_SNDTIMEO                      = 21,
+               SO_SECURITY_AUTHENTICATION       = 22,
+               SO_SECURITY_ENCRYPTION_TRANSPORT = 23,
+               SO_SECURITY_ENCRYPTION_NETWORK   = 24,
+               SO_BINDTODEVICE                  = 25,
+               SO_ATTACH_FILTER                 = 26,
+               SO_DETACH_FILTER                 = 27,
+               SO_PEERNAME                      = 28,
+               SO_TIMESTAMP                     = 29,
+               SO_ACCEPTCONN                    = 30,
+               SO_PEERSEC                       = 31,
+               SO_PASSSEC                       = 34,
+               SO_TIMESTAMPNS                   = 35,
+               SO_MARK                          = 36,
+               SO_TIMESTAMPING                  = 37,
+               SO_PROTOCOL                      = 38,
+               SO_DOMAIN                        = 39,
+               SO_RXQ_OVFL                      = 40,
+               SO_WIFI_STATUS                   = 41,
+               SO_PEEK_OFF                      = 42,
+               SO_NOFCS                         = 43,
+               SO_LOCK_FILTER                   = 44,
+               SO_SELECT_ERR_QUEUE              = 45,
+               SO_BUSY_POLL                     = 46,
+               SO_MAX_PACING_RATE               = 47,
+       }
+
+       [Flags][Map]
+       [CLSCompliant (false)]
+       public enum MessageFlags : int {
+               MSG_OOB          =       0x01, /* Process out-of-band data. */
+               MSG_PEEK         =       0x02, /* Peek at incoming messages. */
+               MSG_DONTROUTE    =       0x04, /* Don't use local routing. */
+               MSG_CTRUNC       =       0x08, /* Control data lost before delivery. */
+               MSG_PROXY        =       0x10, /* Supply or ask second address. */
+               MSG_TRUNC        =       0x20,
+               MSG_DONTWAIT     =       0x40, /* Nonblocking IO. */
+               MSG_EOR          =       0x80, /* End of record. */
+               MSG_WAITALL      =      0x100, /* Wait for a full request. */
+               MSG_FIN          =      0x200,
+               MSG_SYN          =      0x400,
+               MSG_CONFIRM      =      0x800, /* Confirm path validity. */
+               MSG_RST          =     0x1000,
+               MSG_ERRQUEUE     =     0x2000, /* Fetch message from error queue. */
+               MSG_NOSIGNAL     =     0x4000, /* Do not generate SIGPIPE. */
+               MSG_MORE         =     0x8000, /* Sender will send more. */
+               MSG_WAITFORONE   =    0x10000, /* Wait for at least one packet to return.*/
+               MSG_FASTOPEN     = 0x20000000, /* Send data in TCP SYN. */
+               MSG_CMSG_CLOEXEC = 0x40000000, /* Set close_on_exit for file descriptor received through SCM_RIGHTS. */
+       }
+
+       [Map]
+       [CLSCompliant (false)]
+       public enum ShutdownOption : int {
+               SHUT_RD   = 0x01,   /* No more receptions. */
+               SHUT_WR   = 0x02,   /* No more transmissions. */
+               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
 
        [Map ("struct flock")]
        public struct Flock
-#if NET_2_0
                : IEquatable <Flock>
-#endif
        {
                [CLSCompliant (false)]
                public LockType         l_type;    // Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
@@ -769,9 +977,7 @@ namespace Mono.Unix.Native {
 
        [Map ("struct pollfd")]
        public struct Pollfd
-#if NET_2_0
                : IEquatable <Pollfd>
-#endif
        {
                public int fd;
                [CLSCompliant (false)]
@@ -808,11 +1014,9 @@ namespace Mono.Unix.Native {
                }
        }
 
-       [Map ("struct stat")]
+       // Use manually written To/From methods to handle fields st_atime_nsec etc.
        public struct Stat
-#if NET_2_0
                : IEquatable <Stat>
-#endif
        {
                [CLSCompliant (false)]
                [dev_t]     public ulong    st_dev;     // device
@@ -838,6 +1042,39 @@ namespace Mono.Unix.Native {
                [time_t]    public  long    st_atime;   // time of last access
                [time_t]    public  long    st_mtime;   // time of last modification
                [time_t]    public  long    st_ctime;   // time of last status change
+               public  long             st_atime_nsec; // Timespec.tv_nsec partner to st_atime
+               public  long             st_mtime_nsec; // Timespec.tv_nsec partner to st_mtime
+               public  long             st_ctime_nsec; // Timespec.tv_nsec partner to st_ctime
+
+               public Timespec st_atim {
+                       get {
+                               return new Timespec { tv_sec = st_atime, tv_nsec = st_atime_nsec };
+                       }
+                       set {
+                               st_atime = value.tv_sec;
+                               st_atime_nsec = value.tv_nsec;
+                       }
+               }
+
+               public Timespec st_mtim {
+                       get {
+                               return new Timespec { tv_sec = st_mtime, tv_nsec = st_mtime_nsec };
+                       }
+                       set {
+                               st_mtime = value.tv_sec;
+                               st_mtime_nsec = value.tv_nsec;
+                       }
+               }
+
+               public Timespec st_ctim {
+                       get {
+                               return new Timespec { tv_sec = st_ctime, tv_nsec = st_ctime_nsec };
+                       }
+                       set {
+                               st_ctime = value.tv_sec;
+                               st_ctime_nsec = value.tv_nsec;
+                       }
+               }
 
                public override int GetHashCode ()
                {
@@ -853,7 +1090,10 @@ namespace Mono.Unix.Native {
                                st_blocks.GetHashCode () ^
                                st_atime.GetHashCode () ^
                                st_mtime.GetHashCode () ^
-                               st_ctime.GetHashCode ();
+                               st_ctime.GetHashCode () ^
+                               st_atime_nsec.GetHashCode () ^
+                               st_mtime_nsec.GetHashCode () ^
+                               st_ctime_nsec.GetHashCode ();
                }
 
                public override bool Equals (object obj)
@@ -873,7 +1113,10 @@ namespace Mono.Unix.Native {
                                value.st_blocks == st_blocks &&
                                value.st_atime == st_atime &&
                                value.st_mtime == st_mtime &&
-                               value.st_ctime == st_ctime;
+                               value.st_ctime == st_ctime &&
+                               value.st_atime_nsec == st_atime_nsec &&
+                               value.st_mtime_nsec == st_mtime_nsec &&
+                               value.st_ctime_nsec == st_ctime_nsec;
                }
 
                public bool Equals (Stat value)
@@ -890,7 +1133,10 @@ namespace Mono.Unix.Native {
                                value.st_blocks == st_blocks &&
                                value.st_atime == st_atime &&
                                value.st_mtime == st_mtime &&
-                               value.st_ctime == st_ctime;
+                               value.st_ctime == st_ctime &&
+                               value.st_atime_nsec == st_atime_nsec &&
+                               value.st_mtime_nsec == st_mtime_nsec &&
+                               value.st_ctime_nsec == st_ctime_nsec;
                }
 
                public static bool operator== (Stat lhs, Stat rhs)
@@ -908,9 +1154,7 @@ namespace Mono.Unix.Native {
        [Map]
        [CLSCompliant (false)]
        public struct Statvfs
-#if NET_2_0
                : IEquatable <Statvfs>
-#endif
        {
                public                  ulong f_bsize;    // file system block size
                public                  ulong f_frsize;   // fragment size
@@ -985,9 +1229,7 @@ namespace Mono.Unix.Native {
 
        [Map ("struct timeval")]
        public struct Timeval
-#if NET_2_0
                : IEquatable <Timeval>
-#endif
        {
                [time_t]      public long tv_sec;   // seconds
                [suseconds_t] public long tv_usec;  // microseconds
@@ -1023,9 +1265,7 @@ namespace Mono.Unix.Native {
 
        [Map ("struct timezone")]
        public struct Timezone
-#if NET_2_0
                : IEquatable <Timezone>
-#endif
        {
                public  int tz_minuteswest; // minutes W of Greenwich
 #pragma warning disable 169            
@@ -1063,9 +1303,7 @@ namespace Mono.Unix.Native {
 
        [Map ("struct utimbuf")]
        public struct Utimbuf
-#if NET_2_0
                : IEquatable <Utimbuf>
-#endif
        {
                [time_t] public long    actime;   // access time
                [time_t] public long    modtime;  // modification time
@@ -1101,9 +1339,7 @@ namespace Mono.Unix.Native {
 
        [Map ("struct timespec")]
        public struct Timespec
-#if NET_2_0
                : IEquatable <Timespec>
-#endif
        {
                [time_t] public long    tv_sec;   // Seconds.
                public          long    tv_nsec;  // Nanoseconds.
@@ -1137,6 +1373,14 @@ namespace Mono.Unix.Native {
                }
        }
 
+       [Map ("struct iovec")]
+       public struct Iovec
+       {
+               public IntPtr   iov_base; // Starting address
+               [CLSCompliant (false)]
+               public ulong    iov_len;  // Number of bytes to transfer
+       }
+
        [Flags][Map]
        public enum EpollFlags {
                EPOLL_CLOEXEC = 02000000,
@@ -1181,14 +1425,158 @@ namespace Mono.Unix.Native {
                [FieldOffset (4)]
                public ulong u64;
        }
+
+       [Map ("struct linger")]
+       [CLSCompliant (false)]
+       public struct Linger {
+               public int l_onoff;
+               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
 
        public sealed class Dirent
-#if NET_2_0
                : IEquatable <Dirent>
-#endif
        {
                [CLSCompliant (false)]
                public /* ino_t */ ulong  d_ino;
@@ -1239,9 +1627,7 @@ namespace Mono.Unix.Native {
        }
 
        public sealed class Fstab
-#if NET_2_0
                : IEquatable <Fstab>
-#endif
        {
                public string fs_spec;
                public string fs_file;
@@ -1293,9 +1679,7 @@ namespace Mono.Unix.Native {
        }
 
        public sealed class Group
-#if NET_2_0
                : IEquatable <Group>
-#endif
        {
                public string           gr_name;
                public string           gr_passwd;
@@ -1375,9 +1759,7 @@ namespace Mono.Unix.Native {
        }
 
        public sealed class Passwd
-#if NET_2_0
                : IEquatable <Passwd>
-#endif
        {
                public string           pw_name;
                public string           pw_passwd;
@@ -1434,9 +1816,7 @@ namespace Mono.Unix.Native {
        }
 
        public sealed class Utsname
-#if NET_2_0
                : IEquatable <Utsname>
-#endif
        {
                public string sysname;
                public string nodename;
@@ -1485,129 +1865,645 @@ namespace Mono.Unix.Native {
                }
        }
 
-       //
-       // 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.
-       //
-       // For example, the man page should be similar to:
-       //
-       //    CONFORMING TO (or CONFORMS TO)
-       //           XPG2, SUSv2, POSIX, etc.
-       //
-       // BSD- and GNU-specific exports can also be placed here.
-       //
-       // Non-POSIX/XPG/etc. functions can also be placed here if:
-       //  (a) They'd be likely to be covered in a Steven's-like book
-       //  (b) The functions would be present in libc.so (or equivalent).
-       //
-       // If a function has its own library, that's a STRONG indicator that the
-       // function should get a different binding, probably in its own assembly, 
-       // so that package management can work sanely.  (That is, we'd like to avoid
-       // scenarios where FooLib.dll is installed, but it requires libFooLib.so to
-       // run, and libFooLib.so doesn't exist.  That would be confusing.)
-       //
-       // The only methods in here should be:
-       //  (1) low-level functions
-       //  (2) "Trivial" function overloads.  For example, if the parameters to a
-       //      function are related (e.g. getgroups(2))
-       //  (3) The return type SHOULD NOT be changed.  If you want to provide a
-       //      convenience function with a nicer return type, place it into one of
-       //      the Mono.Unix.Unix* wrapper classes, and give it a .NET-styled name.
-       //      - EXCEPTION: No public functions should have a `void' return type.
-       //        `void' return types should be replaced with `int'.
-       //        Rationality: `void'-return functions typically require a
-       //        complicated call sequence, such as clear errno, then call, then
-       //        check errno to see if any errors occurred.  This sequence can't 
-       //        be done safely in managed code, as errno may change as part of 
-       //        the P/Invoke mechanism.
-       //        Instead, add a MonoPosixHelper export which does:
-       //          errno = 0;
-       //          INVOKE SYSCALL;
-       //          return errno == 0 ? 0 : -1;
-       //        This lets managed code check the return value in the usual manner.
-       //  (4) Exceptions SHOULD NOT be thrown.  EXCEPTIONS: 
-       //      - If you're wrapping *broken* methods which make assumptions about 
-       //        input data, such as that an argument refers to N bytes of data.  
-       //        This is currently limited to cuserid(3) and encrypt(3).
-       //      - If you call functions which themselves generate exceptions.  
-       //        This is the case for using NativeConvert, which will throw an
-       //        exception if an invalid/unsupported value is used.
-       //
-       // Naming Conventions:
-       //  - Syscall method names should have the same name as the function being
-       //    wrapped (e.g. Syscall.read ==> read(2)).  This allows people to
-       //    consult the appropriate man page if necessary.
-       //  - Methods need not have the same arguments IF this simplifies or
-       //    permits correct usage.  The current example is syslog, in which
-       //    syslog(3)'s single `priority' argument is split into SyslogFacility
-       //    and SyslogLevel arguments.
-       //  - Type names (structures, classes, enumerations) are always PascalCased.
-       //  - Enumerations are named as <MethodName><ArgumentName>, and are located
-       //    in the Mono.Unix.Native namespace.  For readability, if ArgumentName 
-       //    is "cmd", use Command instead.  For example, fcntl(2) takes a
-       //    FcntlCommand argument.  This naming convention is to provide an
-       //    assocation between an enumeration and where it should be used, and
-       //    allows a single method to accept multiple different enumerations 
-       //    (see mmap(2), which takes MmapProts and MmapFlags).
-       //    - EXCEPTION: if an enumeration is shared between multiple different
-       //      methods, AND/OR the "obvious" enumeration name conflicts with an
-       //      existing .NET type, a more appropriate name should be used.
-       //      Example: FilePermissions
-       //    - EXCEPTION: [Flags] enumerations should get plural names to follow
-       //      .NET name guidelines.  Usually this doesn't result in a change
-       //      (OpenFlags is the `flags' parameter for open(2)), but it can
-       //      (mmap(2) prot ==> MmapProts, access(2) mode ==> AccessModes).
-       //  - Enumerations should have the [Map] and (optional) [Flags] attributes.
-       //    [Map] is required for make-map to find the type and generate the
-       //    appropriate NativeConvert conversion functions.
-       //  - Enumeration contents should match the original Unix names.  This helps
-       //    with documentation (the existing man pages are still useful), and is
-       //    required for use with the make-map generation program.
-       //  - Structure names should be the PascalCased version of the actual
-       //    structure name (struct flock ==> Flock).  Structure members should
-       //    have the same names, or a (reasonably) portable subset (Dirent being
-       //    the poster child for questionable members).
-       //    - Whether the managed type should be a reference type (class) or a 
-       //      value type (struct) should be determined on a case-by-case basis: 
-       //      if you ever need to be able to use NULL for it (such as with Dirent, 
-       //      Group, Passwd, as these are method return types and `null' is used 
-       //      to signify the end), it should be a reference type; otherwise, use 
-       //      your discretion, and keep any expected usage patterns in mind.
-       //  - Syscall should be a Single Point Of Truth (SPOT).  There should be
-       //    only ONE way to do anything.  By convention, the Linux function names
-       //    are used, but that need not always be the case (use your discretion).
-       //    It SHOULD NOT be required that developers know what platform they're
-       //    on, and choose among a set of similar functions.  In short, anything
-       //    that requires a platform check is BAD -- Mono.Unix is a wrapper, and
-       //    we can afford to clean things up whenever possible.
-       //    - Examples: 
-       //      - Syscall.statfs: Solaris/Mac OS X provide statfs(2), Linux provides
-       //        statvfs(2).  MonoPosixHelper will "thunk" between the two,
-       //        exporting a statvfs that works across platforms.
-       //      - Syscall.getfsent: Glibc export which Solaris lacks, while Solaris
-       //        instead provides getvfsent(3).  MonoPosixHelper provides wrappers
-       //        to convert getvfsent(3) into Fstab data.
-       //    - Exception: If it isn't possible to cleanly wrap platforms, then the
-       //      method shouldn't be exported.  The user will be expected to do their
-       //      own platform check and their own DllImports.
-       //      Examples: mount(2), umount(2), etc.
-       //    - Note: if a platform doesn't support a function AT ALL, the
-       //      MonoPosixHelper wrapper won't be compiled, resulting in a
-       //      EntryPointNotFoundException.  This is also consistent with a missing 
-       //      P/Invoke into libc.so.
-       //
+       // 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)]
-       public sealed class Syscall : Stdlib
-       {
-               new internal const string LIBC  = "libc";
+       [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;
 
-               private Syscall () {}
+               public UnixAddressFamily sa_family {
+                       get { return _sa_family; }
+                       set { _sa_family = value; }
+               }
 
-               //
-               // <aio.h>
-               //
+               public Sockaddr ()
+               {
+                       this.type = SockaddrType.Sockaddr;
+                       this.sa_family = UnixAddressFamily.AF_UNSPEC;
+               }
 
-               // TODO: aio_cancel(3), aio_error(3), aio_fsync(3), aio_read(3), 
+               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.
+       //
+       // For example, the man page should be similar to:
+       //
+       //    CONFORMING TO (or CONFORMS TO)
+       //           XPG2, SUSv2, POSIX, etc.
+       //
+       // BSD- and GNU-specific exports can also be placed here.
+       //
+       // Non-POSIX/XPG/etc. functions can also be placed here if:
+       //  (a) They'd be likely to be covered in a Steven's-like book
+       //  (b) The functions would be present in libc.so (or equivalent).
+       //
+       // If a function has its own library, that's a STRONG indicator that the
+       // function should get a different binding, probably in its own assembly, 
+       // so that package management can work sanely.  (That is, we'd like to avoid
+       // scenarios where FooLib.dll is installed, but it requires libFooLib.so to
+       // run, and libFooLib.so doesn't exist.  That would be confusing.)
+       //
+       // The only methods in here should be:
+       //  (1) low-level functions
+       //  (2) "Trivial" function overloads.  For example, if the parameters to a
+       //      function are related (e.g. getgroups(2))
+       //  (3) The return type SHOULD NOT be changed.  If you want to provide a
+       //      convenience function with a nicer return type, place it into one of
+       //      the Mono.Unix.Unix* wrapper classes, and give it a .NET-styled name.
+       //      - EXCEPTION: No public functions should have a `void' return type.
+       //        `void' return types should be replaced with `int'.
+       //        Rationality: `void'-return functions typically require a
+       //        complicated call sequence, such as clear errno, then call, then
+       //        check errno to see if any errors occurred.  This sequence can't 
+       //        be done safely in managed code, as errno may change as part of 
+       //        the P/Invoke mechanism.
+       //        Instead, add a MonoPosixHelper export which does:
+       //          errno = 0;
+       //          INVOKE SYSCALL;
+       //          return errno == 0 ? 0 : -1;
+       //        This lets managed code check the return value in the usual manner.
+       //  (4) Exceptions SHOULD NOT be thrown.  EXCEPTIONS: 
+       //      - If you're wrapping *broken* methods which make assumptions about 
+       //        input data, such as that an argument refers to N bytes of data.  
+       //        This is currently limited to cuserid(3) and encrypt(3).
+       //      - If you call functions which themselves generate exceptions.  
+       //        This is the case for using NativeConvert, which will throw an
+       //        exception if an invalid/unsupported value is used.
+       //
+       // Naming Conventions:
+       //  - Syscall method names should have the same name as the function being
+       //    wrapped (e.g. Syscall.read ==> read(2)).  This allows people to
+       //    consult the appropriate man page if necessary.
+       //  - Methods need not have the same arguments IF this simplifies or
+       //    permits correct usage.  The current example is syslog, in which
+       //    syslog(3)'s single `priority' argument is split into SyslogFacility
+       //    and SyslogLevel arguments.
+       //  - Type names (structures, classes, enumerations) are always PascalCased.
+       //  - Enumerations are named as <MethodName><ArgumentName>, and are located
+       //    in the Mono.Unix.Native namespace.  For readability, if ArgumentName 
+       //    is "cmd", use Command instead.  For example, fcntl(2) takes a
+       //    FcntlCommand argument.  This naming convention is to provide an
+       //    assocation between an enumeration and where it should be used, and
+       //    allows a single method to accept multiple different enumerations 
+       //    (see mmap(2), which takes MmapProts and MmapFlags).
+       //    - EXCEPTION: if an enumeration is shared between multiple different
+       //      methods, AND/OR the "obvious" enumeration name conflicts with an
+       //      existing .NET type, a more appropriate name should be used.
+       //      Example: FilePermissions
+       //    - EXCEPTION: [Flags] enumerations should get plural names to follow
+       //      .NET name guidelines.  Usually this doesn't result in a change
+       //      (OpenFlags is the `flags' parameter for open(2)), but it can
+       //      (mmap(2) prot ==> MmapProts, access(2) mode ==> AccessModes).
+       //  - Enumerations should have the [Map] and (optional) [Flags] attributes.
+       //    [Map] is required for make-map to find the type and generate the
+       //    appropriate NativeConvert conversion functions.
+       //  - Enumeration contents should match the original Unix names.  This helps
+       //    with documentation (the existing man pages are still useful), and is
+       //    required for use with the make-map generation program.
+       //  - Structure names should be the PascalCased version of the actual
+       //    structure name (struct flock ==> Flock).  Structure members should
+       //    have the same names, or a (reasonably) portable subset (Dirent being
+       //    the poster child for questionable members).
+       //    - Whether the managed type should be a reference type (class) or a 
+       //      value type (struct) should be determined on a case-by-case basis: 
+       //      if you ever need to be able to use NULL for it (such as with Dirent, 
+       //      Group, Passwd, as these are method return types and `null' is used 
+       //      to signify the end), it should be a reference type; otherwise, use 
+       //      your discretion, and keep any expected usage patterns in mind.
+       //  - Syscall should be a Single Point Of Truth (SPOT).  There should be
+       //    only ONE way to do anything.  By convention, the Linux function names
+       //    are used, but that need not always be the case (use your discretion).
+       //    It SHOULD NOT be required that developers know what platform they're
+       //    on, and choose among a set of similar functions.  In short, anything
+       //    that requires a platform check is BAD -- Mono.Unix is a wrapper, and
+       //    we can afford to clean things up whenever possible.
+       //    - Examples: 
+       //      - Syscall.statfs: Solaris/Mac OS X provide statfs(2), Linux provides
+       //        statvfs(2).  MonoPosixHelper will "thunk" between the two,
+       //        exporting a statvfs that works across platforms.
+       //      - Syscall.getfsent: Glibc export which Solaris lacks, while Solaris
+       //        instead provides getvfsent(3).  MonoPosixHelper provides wrappers
+       //        to convert getvfsent(3) into Fstab data.
+       //    - Exception: If it isn't possible to cleanly wrap platforms, then the
+       //      method shouldn't be exported.  The user will be expected to do their
+       //      own platform check and their own DllImports.
+       //      Examples: mount(2), umount(2), etc.
+       //    - Note: if a platform doesn't support a function AT ALL, the
+       //      MonoPosixHelper wrapper won't be compiled, resulting in a
+       //      EntryPointNotFoundException.  This is also consistent with a missing 
+       //      P/Invoke into libc.so.
+       //
+       [CLSCompliant (false)]
+       public sealed class Syscall : Stdlib
+       {
+               new internal const string LIBC  = "libc";
+
+               private Syscall () {}
+
+               //
+               // <aio.h>
+               //
+
+               // TODO: aio_cancel(3), aio_error(3), aio_fsync(3), aio_read(3), 
                // aio_return(3), aio_suspend(3), aio_write(3)
                //
                // Then update UnixStream.BeginRead to use the aio* functions.
@@ -2005,6 +2901,9 @@ namespace Mono.Unix.Native {
 
                [DllImport (LIBC, SetLastError=true)]
                public static extern int dirfd (IntPtr dir);
+
+               [DllImport (LIBC, SetLastError=true)]
+               public static extern IntPtr fdopendir (int fd);
                #endregion
 
                #region <fcntl.h> Declarations
@@ -2020,6 +2919,14 @@ namespace Mono.Unix.Native {
                                EntryPoint="Mono_Posix_Syscall_fcntl_arg")]
                public static extern int fcntl (int fd, FcntlCommand cmd, long arg);
 
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_fcntl_arg_int")]
+               public static extern int fcntl (int fd, FcntlCommand cmd, int arg);
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_fcntl_arg_ptr")]
+               public static extern int fcntl (int fd, FcntlCommand cmd, IntPtr ptr);
+
                public static int fcntl (int fd, FcntlCommand cmd, DirectoryNotifyFlags arg)
                {
                        if (cmd != FcntlCommand.F_NOTIFY) {
@@ -2068,6 +2975,40 @@ namespace Mono.Unix.Native {
                [DllImport (MPH, SetLastError=true, 
                                EntryPoint="Mono_Posix_Syscall_posix_fallocate")]
                public static extern int posix_fallocate (int fd, long offset, ulong len);
+
+               [DllImport (LIBC, SetLastError=true, 
+                               EntryPoint="openat")]
+               private static extern int sys_openat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, int flags);
+
+               // openat(2)
+               //    int openat(int dirfd, const char *pathname, int flags, mode_t mode);
+               [DllImport (LIBC, SetLastError=true, 
+                               EntryPoint="openat")]
+               private static extern int sys_openat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, int flags, uint mode);
+
+               public static int openat (int dirfd, string pathname, OpenFlags flags)
+               {
+                       int _flags = NativeConvert.FromOpenFlags (flags);
+                       return sys_openat (dirfd, pathname, _flags);
+               }
+
+               public static int openat (int dirfd, string pathname, OpenFlags flags, FilePermissions mode)
+               {
+                       int _flags = NativeConvert.FromOpenFlags (flags);
+                       uint _mode = NativeConvert.FromFilePermissions (mode);
+                       return sys_openat (dirfd, pathname, _flags, _mode);
+               }
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_get_at_fdcwd")]
+               private static extern int get_at_fdcwd ();
+
+               public static readonly int AT_FDCWD = get_at_fdcwd ();
+
                #endregion
 
                #region <fstab.h> Declarations
@@ -2193,7 +3134,7 @@ namespace Mono.Unix.Native {
                //
                // TODO: putgrent(3), fgetgrent_r(), initgroups(3)
 
-               // getgrouplist(2) 
+               // getgrouplist(2)
                [DllImport (LIBC, SetLastError=true, EntryPoint="getgrouplist")]
                private static extern int sys_getgrouplist (string user, uint grp, uint [] groups,ref int ngroups);
 
@@ -2206,7 +3147,7 @@ namespace Mono.Unix.Native {
                        // Syscall to getpwnam to retrieve user uid
                        Passwd pw = Syscall.getpwnam (username);
                        if (pw == null)
-                               throw new ArgumentException (string.Format ("User {0} does not exists",username), "username");
+                               throw new ArgumentException (string.Format ("User {0} does not exist", username), "username");
                        return getgrouplist (pw);
                }
 
@@ -2228,7 +3169,7 @@ namespace Mono.Unix.Native {
                        Group gr = null;
                        for (int i = 0; i < res; i++) {
                                gr = Syscall.getgrgid (groups [i]);
-                               if (gr != null) 
+                               if (gr != null)
                                        result.Add (gr);
                        }
                        return result.ToArray ();
@@ -2236,7 +3177,8 @@ namespace Mono.Unix.Native {
 
                // setgroups(2)
                //    int setgroups (size_t size, const gid_t *list);
-               [DllImport (MPH, SetLastError=true, EntryPoint="Mono_Posix_Syscall_setgroups")]
+               [DllImport (MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_Syscall_setgroups")]
                public static extern int setgroups (ulong size, uint[] list);
 
                public static int setgroups (uint [] list)
@@ -2663,6 +3605,12 @@ namespace Mono.Unix.Native {
                        }
                }
 
+               [DllImport (LIBC, SetLastError=true)]
+               public static extern int renameat (int olddirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string oldpath, int newdirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string newpath);
                #endregion
 
                #region <stdlib.h> Declarations
@@ -2672,6 +3620,16 @@ namespace Mono.Unix.Native {
                [DllImport (LIBC, SetLastError=true)]
                public static extern int mkstemp (StringBuilder template);
 
+               [DllImport (LIBC, SetLastError=true, EntryPoint="mkdtemp")]
+               private static extern IntPtr sys_mkdtemp (StringBuilder template);
+
+               public static StringBuilder mkdtemp (StringBuilder template)
+               {
+                       if (sys_mkdtemp (template) == IntPtr.Zero)
+                               return null;
+                       return template;
+               }
+
                [DllImport (LIBC, SetLastError=true)]
                public static extern int ttyslot ();
 
@@ -2726,7 +3684,7 @@ namespace Mono.Unix.Native {
                        ee.events = events;
                        ee.fd = fd;
 
-                       return sys_epoll_ctl (epfd, op, fd, ref ee);
+                       return epoll_ctl (epfd, op, fd, ref ee);
                }
 
                public static int epoll_wait (int epfd, EpollEvent [] events, int max_events, int timeout)
@@ -2744,7 +3702,7 @@ namespace Mono.Unix.Native {
                private static extern int sys_epoll_create1 (EpollFlags flags);
 
                [DllImport (LIBC, SetLastError=true, EntryPoint="epoll_ctl")]
-               private static extern int sys_epoll_ctl (int epfd, EpollOp op, int fd, ref EpollEvent ee);
+               public static extern int epoll_ctl (int epfd, EpollOp op, int fd, ref EpollEvent ee);
 
                [DllImport (LIBC, SetLastError=true, EntryPoint="epoll_wait")]
                private static extern int sys_epoll_wait (int epfd, EpollEvent [] ee, int maxevents, int timeout);
@@ -2961,24 +3919,118 @@ namespace Mono.Unix.Native {
                // mknod(2)
                //    int mknod (const char *pathname, mode_t mode, dev_t dev);
                [DllImport (MPH, SetLastError=true,
-                               EntryPoint="Mono_Posix_Syscall_mknod")]
-               public static extern int mknod (
+                               EntryPoint="Mono_Posix_Syscall_mknod")]
+               public static extern int mknod (
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, FilePermissions mode, ulong dev);
+
+               // mkfifo(3)
+               //    int mkfifo(const char *pathname, mode_t mode);
+               [DllImport (LIBC, SetLastError=true, EntryPoint="mkfifo")]
+               private static extern int sys_mkfifo (
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, uint mode);
+
+               public static int mkfifo (string pathname, FilePermissions mode)
+               {
+                       uint _mode = NativeConvert.FromFilePermissions (mode);
+                       return sys_mkfifo (pathname, _mode);
+               }
+
+               // fchmodat(2)
+               //    int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
+               [DllImport (LIBC, SetLastError=true, EntryPoint="fchmodat")]
+               private static extern int sys_fchmodat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, uint mode, int flags);
+
+               public static int fchmodat (int dirfd, string pathname, FilePermissions mode, AtFlags flags)
+               {
+                       uint _mode = NativeConvert.FromFilePermissions (mode);
+                       int _flags = NativeConvert.FromAtFlags (flags);
+                       return sys_fchmodat (dirfd, pathname, _mode, _flags);
+               }
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_fstatat")]
+               public static extern int fstatat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string file_name, out Stat buf, AtFlags flags);
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_get_utime_now")]
+               private static extern long get_utime_now ();
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_get_utime_omit")]
+               private static extern long get_utime_omit ();
+
+               public static readonly long UTIME_NOW = get_utime_now ();
+
+               public static readonly long UTIME_OMIT = get_utime_omit ();
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_futimens")]
+               private static extern int sys_futimens (int fd, Timespec[] times);
+
+               public static int futimens (int fd, Timespec[] times)
+               {
+                       if (times != null && times.Length != 2) {
+                               SetLastError (Errno.EINVAL);
+                               return -1;
+                       }
+                       return sys_futimens (fd, times);
+               }
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_utimensat")]
+               private static extern int sys_utimensat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, Timespec[] times, int flags);
+
+               public static int utimensat (int dirfd, string pathname, Timespec[] times, AtFlags flags)
+               {
+                       if (times != null && times.Length != 2) {
+                               SetLastError (Errno.EINVAL);
+                               return -1;
+                       }
+                       int _flags = NativeConvert.FromAtFlags (flags);
+                       return sys_utimensat (dirfd, pathname, times, _flags);
+               }
+
+               // mkdirat(2)
+               //    int mkdirat(int dirfd, const char *pathname, mode_t mode);
+               [DllImport (LIBC, SetLastError=true, EntryPoint="mkdirat")]
+               private static extern int sys_mkdirat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string oldpath, uint mode);
+
+               public static int mkdirat (int dirfd, string oldpath, FilePermissions mode)
+               {
+                       uint _mode = NativeConvert.FromFilePermissions (mode);
+                       return sys_mkdirat (dirfd, oldpath, _mode);
+               }
+
+               // mknodat(2)
+               //    int mknodat (int dirfd, const char *pathname, mode_t mode, dev_t dev);
+               [DllImport (MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_Syscall_mknodat")]
+               public static extern int mknodat (int dirfd,
                                [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
                                string pathname, FilePermissions mode, ulong dev);
 
-               // mkfifo(3)
-               //    int mkfifo(const char *pathname, mode_t mode);
-               [DllImport (LIBC, SetLastError=true, EntryPoint="mkfifo")]
-               private static extern int sys_mkfifo (
+               // mkfifoat(3)
+               //    int mkfifoat(int dirfd, const char *pathname, mode_t mode);
+               [DllImport (LIBC, SetLastError=true, EntryPoint="mkfifoat")]
+               private static extern int sys_mkfifoat (int dirfd,
                                [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
                                string pathname, uint mode);
 
-               public static int mkfifo (string pathname, FilePermissions mode)
+               public static int mkfifoat (int dirfd, string pathname, FilePermissions mode)
                {
                        uint _mode = NativeConvert.FromFilePermissions (mode);
-                       return sys_mkfifo (pathname, _mode);
+                       return sys_mkfifoat (dirfd, pathname, _mode);
                }
-
                #endregion
 
                #region <sys/stat.h> Declarations
@@ -3727,17 +4779,51 @@ namespace Mono.Unix.Native {
                                [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
                                string newpath);
 
+               delegate long DoReadlinkFun (byte[] target);
+
+               // Helper function for readlink(string, StringBuilder) and readlinkat (int, string, StringBuilder)
+               static int ReadlinkIntoStringBuilder (DoReadlinkFun doReadlink, [Out] StringBuilder buf, ulong bufsiz)
+               {
+                       // bufsiz > int.MaxValue can't work because StringBuilder can store only int.MaxValue chars
+                       int bufsizInt = checked ((int) bufsiz);
+                       var target = new byte [bufsizInt];
+
+                       var r = doReadlink (target);
+                       if (r < 0)
+                               return checked ((int) r);
+
+                       buf.Length = 0;
+                       var chars = UnixEncoding.Instance.GetChars (target, 0, checked ((int) r));
+                       // Make sure that at more bufsiz chars are written
+                       buf.Append (chars, 0, System.Math.Min (bufsizInt, chars.Length));
+                       if (r == bufsizInt) {
+                               // may not have read full contents; fill 'buf' so that caller can properly check
+                               buf.Append (new string ('\x00', bufsizInt - buf.Length));
+                       }
+                       return buf.Length;
+               }
+
                // readlink(2)
-               //    int readlink(const char *path, char *buf, size_t bufsize);
+               //    ssize_t readlink(const char *path, char *buf, size_t bufsize);
+               public static int readlink (string path, [Out] StringBuilder buf, ulong bufsiz)
+               {
+                       return ReadlinkIntoStringBuilder (target => readlink (path, target), buf, bufsiz);
+               }
+
+               public static int readlink (string path, [Out] StringBuilder buf)
+               {
+                       return readlink (path, buf, (ulong) buf.Capacity);
+               }
+
                [DllImport (MPH, SetLastError=true,
                                EntryPoint="Mono_Posix_Syscall_readlink")]
-               public static extern int readlink (
+               private static extern long readlink (
                                [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
-                               string path, [Out] StringBuilder buf, ulong bufsiz);
+                               string path, byte[] buf, ulong bufsiz);
 
-               public static int readlink (string path, [Out] StringBuilder buf)
+               public static long readlink (string path, byte[] buf)
                {
-                       return readlink (path, buf, (ulong) buf.Capacity);
+                       return readlink (path, buf, (ulong) buf.LongLength);
                }
 
                [DllImport (LIBC, SetLastError=true)]
@@ -3977,6 +5063,84 @@ namespace Mono.Unix.Native {
                        swab ((IntPtr) from, (IntPtr) to, n);
                }
 
+               [DllImport (LIBC, SetLastError=true, EntryPoint="faccessat")]
+               private static extern int sys_faccessat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, int mode, int flags);
+
+               public static int faccessat (int dirfd, string pathname, AccessModes mode, AtFlags flags)
+               {
+                       int _mode = NativeConvert.FromAccessModes (mode);
+                       int _flags = NativeConvert.FromAtFlags (flags);
+                       return sys_faccessat (dirfd, pathname, _mode, _flags);
+               }
+
+               // fchownat(2)
+               //    int fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags);
+               [DllImport (LIBC, SetLastError=true, EntryPoint="fchownat")]
+               private static extern int sys_fchownat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, uint owner, uint group, int flags);
+
+               public static int fchownat (int dirfd, string pathname, uint owner, uint group, AtFlags flags)
+               {
+                       int _flags = NativeConvert.FromAtFlags (flags);
+                       return sys_fchownat (dirfd, pathname, owner, group, _flags);
+               }
+
+               [DllImport (LIBC, SetLastError=true, EntryPoint="linkat")]
+               private static extern int sys_linkat (int olddirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string oldpath, int newdirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string newpath, int flags);
+
+               public static int linkat (int olddirfd, string oldpath, int newdirfd, string newpath, AtFlags flags)
+               {
+                       int _flags = NativeConvert.FromAtFlags (flags);
+                       return sys_linkat (olddirfd, oldpath, newdirfd, newpath, _flags);
+               }
+
+               // readlinkat(2)
+               //    ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize);
+               public static int readlinkat (int dirfd, string pathname, [Out] StringBuilder buf, ulong bufsiz)
+               {
+                       return ReadlinkIntoStringBuilder (target => readlinkat (dirfd, pathname, target), buf, bufsiz);
+               }
+
+               public static int readlinkat (int dirfd, string pathname, [Out] StringBuilder buf)
+               {
+                       return readlinkat (dirfd, pathname, buf, (ulong) buf.Capacity);
+               }
+
+               [DllImport (MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_Syscall_readlinkat")]
+               private static extern long readlinkat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, byte[] buf, ulong bufsiz);
+
+               public static long readlinkat (int dirfd, string pathname, byte[] buf)
+               {
+                       return readlinkat (dirfd, pathname, buf, (ulong) buf.LongLength);
+               }
+
+               [DllImport (LIBC, SetLastError=true)]
+               public static extern int symlinkat (
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string oldpath, int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string newpath);
+
+               [DllImport (LIBC, SetLastError=true, EntryPoint="unlinkat")]
+               private static extern int sys_unlinkat (int dirfd,
+                               [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))]
+                               string pathname, int flags);
+
+               public static int unlinkat (int dirfd, string pathname, AtFlags flags)
+               {
+                       int _flags = NativeConvert.FromAtFlags (flags);
+                       return sys_unlinkat (dirfd, pathname, _flags);
+               }
                #endregion
 
                #region <utime.h> Declarations
@@ -4001,9 +5165,487 @@ namespace Mono.Unix.Native {
                        return sys_utime (filename, ref buf, 0);
                }
                #endregion
+
+               #region <sys/uio.h> Declarations
+               //
+               // <sys/uio.h> -- COMPLETE
+               //
+
+               // readv(2)
+               //    ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
+               [DllImport (MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_Syscall_readv")]
+               private static extern long sys_readv (int fd, Iovec[] iov, int iovcnt);
+
+               public static long readv (int fd, Iovec[] iov)
+               {
+                       return sys_readv (fd, iov, iov.Length);
+               }
+
+               // writev(2)
+               //    ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
+               [DllImport (MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_Syscall_writev")]
+               private static extern long sys_writev (int fd, Iovec[] iov, int iovcnt);
+
+               public static long writev (int fd, Iovec[] iov)
+               {
+                       return sys_writev (fd, iov, iov.Length);
+               }
+
+               // preadv(2)
+               //    ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+               [DllImport (MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_Syscall_preadv")]
+               private static extern long sys_preadv (int fd, Iovec[] iov, int iovcnt, long offset);
+
+               public static long preadv (int fd, Iovec[] iov, long offset)
+               {
+                       return sys_preadv (fd, iov, iov.Length, offset);
+               }
+
+               // pwritev(2)
+               //    ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+               [DllImport (MPH, SetLastError=true,
+                               EntryPoint="Mono_Posix_Syscall_pwritev")]
+               private static extern long sys_pwritev (int fd, Iovec[] iov, int iovcnt, long offset);
+
+               public static long pwritev (int fd, Iovec[] iov, long offset)
+               {
+                       return sys_pwritev (fd, iov, iov.Length, offset);
+               }
+               #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>
+               //
+
+               // socket(2)
+               //    int socket(int domain, int type, int protocol);
+               [DllImport (LIBC, SetLastError=true, 
+                               EntryPoint="socket")]
+               static extern int sys_socket (int domain, int type, int protocol);
+
+               public static int socket (UnixAddressFamily domain, UnixSocketType type, UnixSocketFlags flags, UnixSocketProtocol protocol)
+               {
+                       var _domain = NativeConvert.FromUnixAddressFamily (domain);
+                       var _type = NativeConvert.FromUnixSocketType (type);
+                       var _flags = NativeConvert.FromUnixSocketFlags (flags);
+                       // protocol == 0 is a special case (uses default protocol)
+                       var _protocol = protocol == 0 ? 0 : NativeConvert.FromUnixSocketProtocol (protocol);
+
+                       return sys_socket (_domain, _type | _flags, _protocol);
+               }
+
+               public static int socket (UnixAddressFamily domain, UnixSocketType type, UnixSocketProtocol protocol)
+               {
+                       return socket (domain, type, 0, protocol);
+               }
+
+               // socketpair(2)
+               //    int socketpair(int domain, int type, int protocol, int sv[2]);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_socketpair")]
+               static extern int sys_socketpair (int domain, int type, int protocol, out int socket1, out int socket2);
+
+               public static int socketpair (UnixAddressFamily domain, UnixSocketType type, UnixSocketFlags flags, UnixSocketProtocol protocol, out int socket1, out int socket2)
+               {
+                       var _domain = NativeConvert.FromUnixAddressFamily (domain);
+                       var _type = NativeConvert.FromUnixSocketType (type);
+                       var _flags = NativeConvert.FromUnixSocketFlags (flags);
+                       // protocol == 0 is a special case (uses default protocol)
+                       var _protocol = protocol == 0 ? 0 : NativeConvert.FromUnixSocketProtocol (protocol);
+
+                       return sys_socketpair (_domain, _type | _flags, _protocol, out socket1, out socket2);
+               }
+
+               public static int socketpair (UnixAddressFamily domain, UnixSocketType type, UnixSocketProtocol protocol, out int socket1, out int socket2)
+               {
+                       return socketpair (domain, type, 0, protocol, out socket1, out socket2);
+               }
+
+               // sockatmark(2)
+               //    int sockatmark(int sockfd);
+               [DllImport (LIBC, SetLastError=true)]
+               public static extern int sockatmark (int socket);
+
+               // listen(2)
+               //    int listen(int sockfd, int backlog);
+               [DllImport (LIBC, SetLastError=true)]
+               public static extern int listen (int socket, int backlog);
+
+               // getsockopt(2)
+               //    int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_getsockopt")]
+               static extern unsafe int sys_getsockopt (int socket, int level, int option_name, void *option_value, ref long option_len);
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_getsockopt_timeval")]
+               static extern unsafe int sys_getsockopt_timeval (int socket, int level, int option_name, out Timeval option_value);
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_getsockopt_linger")]
+               static extern unsafe int sys_getsockopt_linger (int socket, int level, int option_name, out Linger option_value);
+
+               public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, void *option_value, ref long option_len)
+               {
+                       var _level = NativeConvert.FromUnixSocketProtocol (level);
+                       var _option_name = NativeConvert.FromUnixSocketOptionName (option_name);
+                       return sys_getsockopt (socket, _level, _option_name, option_value, ref option_len);
+               }
+
+               public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, IntPtr option_value, ref long option_len)
+               {
+                       return getsockopt (socket, level, option_name, (void*) option_value, ref option_len);
+               }
+
+               public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, out int option_value)
+               {
+                       int value;
+                       long size = sizeof (int);
+                       int ret = getsockopt (socket, level, option_name, &value, ref size);
+                       if (ret != -1 && size != sizeof (int)) {
+                               SetLastError (Errno.EINVAL);
+                               ret = -1;
+                       }
+                       option_value = value;
+                       return ret;
+               }
+
+               public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, byte[] option_value, ref long option_len)
+               {
+                       if (option_len > (option_value == null ? 0 : option_value.Length))
+                               throw new ArgumentOutOfRangeException ("option_len", "option_len > (option_value == null ? 0 : option_value.Length)");
+                       fixed (byte* ptr = option_value)
+                               return getsockopt (socket, level, option_name, ptr, ref option_len);
+               }
+
+               public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, out Timeval option_value)
+               {
+                       var _level = NativeConvert.FromUnixSocketProtocol (level);
+                       var _option_name = NativeConvert.FromUnixSocketOptionName (option_name);
+                       return sys_getsockopt_timeval (socket, _level, _option_name, out option_value);
+               }
+
+               public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, out Linger option_value)
+               {
+                       var _level = NativeConvert.FromUnixSocketProtocol (level);
+                       var _option_name = NativeConvert.FromUnixSocketOptionName (option_name);
+                       return sys_getsockopt_linger (socket, _level, _option_name, out option_value);
+               }
+
+               // setsockopt(2)
+               //    int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_setsockopt")]
+               static extern unsafe int sys_setsockopt (int socket, int level, int option_name, void *option_value, long option_len);
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_setsockopt_timeval")]
+               static extern unsafe int sys_setsockopt_timeval (int socket, int level, int option_name, ref Timeval option_value);
+
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_setsockopt_linger")]
+               static extern unsafe int sys_setsockopt_linger (int socket, int level, int option_name, ref Linger option_value);
+
+               public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, void *option_value, long option_len)
+               {
+                       var _level = NativeConvert.FromUnixSocketProtocol (level);
+                       var _option_name = NativeConvert.FromUnixSocketOptionName (option_name);
+                       return sys_setsockopt (socket, _level, _option_name, option_value, option_len);
+               }
+
+               public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, IntPtr option_value, long option_len)
+               {
+                       return setsockopt (socket, level, option_name, (void*) option_value, option_len);
+               }
+
+               public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, int option_value)
+               {
+                       return setsockopt (socket, level, option_name, &option_value, sizeof (int));
+               }
+
+               public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, byte[] option_value, long option_len)
+               {
+                       if (option_len > (option_value == null ? 0 : option_value.Length))
+                               throw new ArgumentOutOfRangeException ("option_len", "option_len > (option_value == null ? 0 : option_value.Length)");
+                       fixed (byte* ptr = option_value)
+                               return setsockopt (socket, level, option_name, ptr, option_len);
+               }
+
+               public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, Timeval option_value)
+               {
+                       var _level = NativeConvert.FromUnixSocketProtocol (level);
+                       var _option_name = NativeConvert.FromUnixSocketOptionName (option_name);
+                       return sys_setsockopt_timeval (socket, _level, _option_name, ref option_value);
+               }
+
+               public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, Linger option_value)
+               {
+                       var _level = NativeConvert.FromUnixSocketProtocol (level);
+                       var _option_name = NativeConvert.FromUnixSocketOptionName (option_name);
+                       return sys_setsockopt_linger (socket, _level, _option_name, ref option_value);
+               }
+
+               // shutdown(2)
+               //    int shutdown(int sockfd, int how);
+               [DllImport (LIBC, SetLastError=true, 
+                               EntryPoint="shutdown")]
+               static extern int sys_shutdown (int socket, int how);
+
+               public static int shutdown (int socket, ShutdownOption how)
+               {
+                       var _how = NativeConvert.FromShutdownOption (how);
+                       return sys_shutdown (socket, _how);
+               }
+
+               // recv(2)
+               //    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_recv")]
+               static extern unsafe long sys_recv (int socket, void *buffer, ulong length, int flags);
+
+               public static unsafe long recv (int socket, void *buffer, ulong length, MessageFlags flags)
+               {
+                       int _flags = NativeConvert.FromMessageFlags (flags);
+                       return sys_recv (socket, buffer, length, _flags);
+               }
+
+               public static unsafe long recv (int socket, IntPtr buffer, ulong length, MessageFlags flags)
+               {
+                       return recv (socket, (void*) buffer, length, flags);
+               }
+
+               public static unsafe long recv (int socket, byte[] buffer, ulong length, MessageFlags flags)
+               {
+                       if (length > (ulong) (buffer == null ? 0 : buffer.LongLength))
+                               throw new ArgumentOutOfRangeException ("length", "length > (buffer == null ? 0 : buffer.LongLength)");
+                       fixed (byte* ptr = buffer)
+                               return recv (socket, ptr, length, flags);
+               }
+
+               // send(2)
+               //    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
+               [DllImport (MPH, SetLastError=true, 
+                               EntryPoint="Mono_Posix_Syscall_send")]
+               static extern unsafe long sys_send (int socket, void *message, ulong length, int flags);
+
+               public static unsafe long send (int socket, void *message, ulong length, MessageFlags flags)
+               {
+                       int _flags = NativeConvert.FromMessageFlags (flags);
+                       return sys_send (socket, message, length, _flags);
+               }
+
+               public static unsafe long send (int socket, IntPtr message, ulong length, MessageFlags flags)
+               {
+                       return send (socket, (void*) message, length, flags);
+               }
+
+               public static unsafe long send (int socket, byte[] message, ulong length, MessageFlags flags)
+               {
+                       if (length > (ulong) (message == null ? 0 : message.LongLength))
+                               throw new ArgumentOutOfRangeException ("length", "length > (message == null ? 0 : message.LongLength)");
+                       fixed (byte* ptr = message)
+                               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
        }
 
        #endregion
 }
 
 // vim: noexpandtab
+// Local Variables: 
+// tab-width: 4
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// End: