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
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
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
[Map ("struct pollfd")]
public struct Pollfd
-#if NET_2_0
: IEquatable <Pollfd>
-#endif
{
public int fd;
[CLSCompliant (false)]
}
}
- [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
[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 ()
{
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)
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)
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)
[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
[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
[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
[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
[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.
}
}
+ [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,
[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;
}
public sealed class Fstab
-#if NET_2_0
: IEquatable <Fstab>
-#endif
{
public string fs_spec;
public string fs_file;
}
public sealed class Group
-#if NET_2_0
: IEquatable <Group>
-#endif
{
public string gr_name;
public string gr_passwd;
}
public sealed class Passwd
-#if NET_2_0
: IEquatable <Passwd>
-#endif
{
public string pw_name;
public string pw_passwd;
}
public sealed class Utsname
-#if NET_2_0
: IEquatable <Utsname>
-#endif
{
public string sysname;
public string nodename;
}
}
- //
- // 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.
[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
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) {
[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
//
// 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);
// 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);
}
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 ();
// 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)
}
}
+ [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
[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 ();
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)
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);
// 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
[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)]
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
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: