Tmds.LibC

Raw bindings to Linux platform APIs for .NET Core.


Keywords
libc, linux
License
MIT
Install
Install-Package Tmds.LibC -Version 0.5.0

Documentation

Travis NuGet

Tmds.LibC

Raw bindings to Linux platform APIs for .NET Core.

Raw bindings

The APIs provided by this package stay as close as possible to the native declarations. Because the native APIs are different per platform (e.g. linux-arm64 vs linux-x64), the package contains separate assemblies for each platform.

.NET Core will use the appropriate assembly based on the rid.

Supported platforms

  • linux x64 glibc
  • linux arm64 glibc
  • linux arm32 glibc

Using this package

Add the package using the dotnet cli:

$ dotnet add package Tmds.LibC

Alternatively, you can use a daily build from the https://www.myget.org/F/tmds/api/v3/index.json NuGet feed.

Program.cs

using System;
using System.Text;
using Tmds.Linux;
using static Tmds.Linux.LibC;

namespace console
{
    class Program
    {
        unsafe static void Main(string[] args)
        {
            var bytes = Encoding.UTF8.GetBytes("Hello world!");
            fixed (byte* buffer = bytes)
            {
                write(STDOUT_FILENO, buffer, bytes.Length);
            }
        }
    }
}

Functions

The following functions are defined in the static class Tmds.Linux.LibC:

_exit, accept, accept4, access, acct, alarm, bind, brk, cfgetispeed, cfgetospeed, cfsetispeed, cfsetospeed, chdir, chmod, chown, chroot, clone, close, confstr, connect, creat, ctermid, daemon, dladdr, dlclose, dlerror, dlinfo, dlopen, dlsym, dlvsym, dup, dup2, dup3, eaccess, epoll_create, epoll_create1, epoll_ctl, epoll_pwait, epoll_wait, euidaccess, execve, faccessat, fallocate, fchdir, fchmod, fchmodat, fchown, fchownat, fcntl, fdatasync, fexecve, fork, fpathconf, fstat, fstatat, fstatvfs, fsync, ftruncate, futimens, getcwd, getdomainname, getdtablesize, getegid, geteuid, getgid, getgroups, gethostid, gethostname, getlogin, getlogin_r, getpagesize, getpeername, getpgid, getpgrp, getpid, getppid, getresgid, getresuid, getsid, getsockname, getsockopt, getuid, htons, io_destroy, io_getevents, io_setup, io_submit, ioctl, isatty, kill, killpg, lchown, link, linkat, listen, lockf, lseek, lstat, mkdir, mkdirat, mkfifo, mkfifoat, mknod, mknodat, name_to_handle_at, nice, ntohs, open, open_by_handle_at, openat, pathconf, pause, pipe, pipe2, posix_fadvise, posix_fallocate, pread, psiginfo, psignal, pthread_kill, pthread_sigmask, pwrite, raise, read, readahead, readlink, readlinkat, recv, recvfrom, recvmsg, rmdir, sbrk, sched_get_priority_max, sched_get_priority_min, sched_getaffinity, sched_getcpu, sched_getscheduler, sched_rr_get_interval, sched_setaffinity, sched_yield, send, sendmsg, sendto, setdomainname, setegid, seteuid, setgid, setgroups, sethostname, setns, setpgid, setpgrp, setregid, setresgid, setresuid, setreuid, setsid, setsockopt, setuid, shutdown, sigaction, sigaddset, sigaltstack, sigandset, sigdelset, sigemptyset, sigfillset, sighold, sigignore, siginterrupt, sigisemptyset, sigismember, sigorset, sigpause, sigpending, sigprocmask, sigqueue, sigrelse, sigsuspend, sigtimedwait, sigwait, sigwaitinfo, sleep, socket, socketpair, splice, stat, statvfs, strerror_r, symlink, symlinkat, sync, sync_file_range, syncfs, syscall, sysconf, tcdrain, tcflow, tcflush, tcgetattr, tcgetpgrp, tcgetsid, tcsendbreak, tcsetattr, tcsetpgrp, tee, truncate, ttyname, ttyname_r, ualarm, umask, unlink, unlinkat, unshare, usleep, utimensat, vfork, vhangup, vmsplice, write,

Structs

The following structs are defined in the Tmds.Linux namespace:

aio_context_t, aio_ring, blkcnt_t, blksize_t, clock_t, cmsghdr, cpu_set_t, dev_t, Dl_info, epoll_data_t, epoll_event, f_owner_ex, file_handle, flock, fsblkcnt_t, fsfilcnt_t, gid_t, group_filter, group_req, group_source_req, in_addr, in_pktinfo, in6_addr, in6_pktinfo, ino_t, io_event, iocb, iovec, ip_mreq, ip_mreq_source, ip_mreqn, ip_opts, ip6_mtuinfo, ipv6_mreq, linger, long_t, mmsghdr, mode_t, msghdr, nlink_t, off_t, pid_t, pthread_t, sa_family_t, scm_timestamping, sigaction, sigevent_t, siginfo_t, sigset_t, sigval, size_t, sock_extended_err, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, sockaddr_un, socklen_t, ssize_t, stack_t, stat, statvfs, syscall_arg, termios, time_t, timespec, ucred, uid_t, ulong_t, winsize,

Examples

This section shows some examples. The examples use a PlatformException class which is implemented as follows:

class PlatformException : Exception
{
    public PlatformException(int errno) :
        base(GetErrorMessage(errno))
    {
        HResult = errno;
    }

    public PlatformException() :
        this(LibC.errno)
    {}

    private unsafe static string GetErrorMessage(int errno)
    {
        int bufferLength = 1024;
        byte* buffer = stackalloc byte[bufferLength];

        int rv = strerror_r(errno, buffer, bufferLength);

        return rv == 0 ? Marshal.PtrToStringAnsi((IntPtr)buffer) : $"errno {errno}";
    }

    public static void Throw() => throw new PlatformException();
}

Example 1: Socket extension method to set raw socket options

static class SocketExtensions
{
    public static unsafe void SetRawSocketOption(this Socket socket, int level, int optname, int optval)
    {
        SafeHandle handle = socket.SafeHandle;
        bool refAdded = false;
        try
        {
            handle.DangerousAddRef(ref refAdded);
            int rv = setsockopt(handle.DangerousGetHandle().ToInt32(), level, optname, &optval, sizeof(int));
            if (rv != 0)
            {
                PlatformException.Throw();
            }
        }
        finally
        {
            if (refAdded)
                handle.DangerousRelease();
        }
    }
}

This extension method can be used with the constants provided by Tmds.LibC, for example:

socket.SetRawSocketOption(SOL_SOCKET, SO_REUSEADDR, 1);

Example 2: Process extension method to request termination

Unix processes can be requested to terminate using the SIGTERM signal. The following code adds an extension method to the Process class to send that signal.

static class ProcessExtensions
{
    public static void Terminate(this Process process)
    {
        if (process.HasExited)
        {
            return;
        }
        int rv = kill(process.Handle.ToInt32(), SIGTERM);
        if (rv == -1 &&
            errno != ESRCH /* process does not exist, assume it exited */)
        {
            PlatformException.Throw();
        }
    }
}

Example 3: Creating a temporary directory that is only accessible by the user

static class FileUtils
{
    public unsafe static string CreatePrivateTempDirectory()
    {
        string path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

        int byteLength = Encoding.UTF8.GetByteCount(path) + 1;
        Span<byte> bytes = byteLength <= 128 ? stackalloc byte[byteLength] : new byte[byteLength];
        Encoding.UTF8.GetBytes(path, bytes);

        fixed (byte* pathname = bytes)
        {
            int rv = mkdir(pathname, S_IRWXU);
            if (rv == -1)
            {
                PlatformException.Throw();
            }
        }

        return path;
    }
}