com.oracle.graal.python.runtime.PosixSupportLibrary Maven / Gradle / Ivy
/*
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.graal.python.runtime;
import static com.oracle.graal.python.runtime.PosixConstants.AF_INET;
import static com.oracle.graal.python.runtime.PosixConstants.AF_INET6;
import static com.oracle.graal.python.runtime.PosixConstants.AF_UNIX;
import static com.oracle.graal.python.runtime.PosixConstants.S_IFBLK;
import static com.oracle.graal.python.runtime.PosixConstants.S_IFCHR;
import static com.oracle.graal.python.runtime.PosixConstants.S_IFDIR;
import static com.oracle.graal.python.runtime.PosixConstants.S_IFIFO;
import static com.oracle.graal.python.runtime.PosixConstants.S_IFLNK;
import static com.oracle.graal.python.runtime.PosixConstants.S_IFMT;
import static com.oracle.graal.python.runtime.PosixConstants.S_IFREG;
import java.nio.ByteBuffer;
import java.util.Arrays;
import com.oracle.graal.python.util.PythonUtils;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.CompilerDirectives.ValueType;
import com.oracle.truffle.api.library.GenerateLibrary;
import com.oracle.truffle.api.library.Library;
import com.oracle.truffle.api.library.LibraryFactory;
import com.oracle.truffle.api.memory.ByteArraySupport;
import com.oracle.truffle.api.strings.TruffleString;
/**
* Internal abstraction layer for POSIX functionality. Instance of the implementation is stored in
* the context. Use {@link PythonContext#getPosixSupport()} to access it.
*/
@GenerateLibrary(receiverType = PosixSupport.class)
public abstract class PosixSupportLibrary extends Library {
public static final char POSIX_FILENAME_SEPARATOR = '/';
// Constants for accessing the fields of the fstat result:
// TODO: have these in posix.c (maybe posix.h) and extract them along with other constants
public static final int ST_MODE = 0;
public static final int ST_SIZE = 6;
public abstract TruffleString getBackend(Object recevier);
public abstract TruffleString strerror(Object receiver, int errorCode);
public abstract long getpid(Object receiver);
public abstract int umask(Object receiver, int mask) throws PosixException;
public abstract int openat(Object receiver, int dirFd, Object pathname, int flags, int mode) throws PosixException;
public abstract int close(Object receiver, int fd) throws PosixException;
public abstract Buffer read(Object receiver, int fd, long length) throws PosixException;
public abstract long write(Object receiver, int fd, Buffer data) throws PosixException;
public abstract int dup(Object receiver, int fd) throws PosixException;
public abstract int dup2(Object receiver, int fd, int fd2, boolean inheritable) throws PosixException;
public abstract boolean getInheritable(Object receiver, int fd) throws PosixException;
public abstract void setInheritable(Object receiver, int fd, boolean inheritable) throws PosixException;
public abstract int[] pipe(Object receiver) throws PosixException;
public abstract SelectResult select(Object receiver, int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException;
public abstract long lseek(Object receiver, int fd, long offset, int how) throws PosixException;
public abstract void ftruncate(Object receiver, int fd, long length) throws PosixException;
public abstract void fsync(Object receiver, int fd) throws PosixException;
public abstract void flock(Object receiver, int fd, int operation) throws PosixException;
public abstract boolean getBlocking(Object receiver, int fd) throws PosixException;
public abstract void setBlocking(Object receiver, int fd, boolean blocking) throws PosixException;
public abstract int[] getTerminalSize(Object receiver, int fd) throws PosixException;
// see stat_struct_to_longs in posix.c for the layout of the array
public abstract long[] fstatat(Object receiver, int dirFd, Object pathname, boolean followSymlinks) throws PosixException;
/**
* Performs operation of fstat(fd).
*
* @param receiver the receiver of the message
* @param fd the file descriptor
* @return see {@code stat_struct_to_longs} in posix.c for the layout of the array. There are
* constants for some of the indices, e.g., {@link #ST_MODE}.
* @throws PosixException if an error occurs
*/
public abstract long[] fstat(Object receiver, int fd) throws PosixException;
public abstract long[] statvfs(Object receiver, Object path) throws PosixException;
public abstract long[] fstatvfs(Object receiver, int fd) throws PosixException;
public abstract Object[] uname(Object receiver) throws PosixException;
public abstract void unlinkat(Object receiver, int dirFd, Object pathname, boolean rmdir) throws PosixException;
public abstract void linkat(Object receiver, int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException;
public abstract void symlinkat(Object receiver, Object target, int linkpathDirFd, Object linkpath) throws PosixException;
public abstract void mkdirat(Object receiver, int dirFd, Object pathname, int mode) throws PosixException;
public abstract Object getcwd(Object receiver) throws PosixException;
public abstract void chdir(Object receiver, Object path) throws PosixException;
/**
* Performs operation of fchdir(fd).
*
* @param receiver the receiver of the message
* @param fd the file descriptor
* @throws PosixException if an error occurs
*/
public abstract void fchdir(Object receiver, int fd) throws PosixException;
public abstract boolean isatty(Object receiver, int fd);
/**
* Caller is responsible for calling {@link #closedir(Object, Object)} to free the allocated
* resources.
*
* @return an opaque directory stream object to be used in calls to {@code readdir} and
* {@code closedir}
*/
public abstract Object opendir(Object receiver, Object path) throws PosixException;
public abstract Object fdopendir(Object receiver, int fd) throws PosixException;
/**
* Implementations must deal with this being called more than once.
*/
public abstract void closedir(Object receiver, Object dirStream) throws PosixException;
/**
* @return an opaque dir entry object to be used in calls to {@code dirEntry*()} methods or
* {@code null} when there are no more items or if the stream has been closed by
* {@code closedir}.
*/
public abstract Object readdir(Object receiver, Object dirStream) throws PosixException;
public abstract void rewinddir(Object receiver, Object dirStream);
/**
* @return an opaque object representing the dir entry name
* @see #getPathAsBytes(Object, Object)
* @see #getPathAsString(Object, Object)
*/
public abstract Object dirEntryGetName(Object receiver, Object dirEntry) throws PosixException;
/**
* Returns the dir entry path, which is the name of the dir entry joined with the given path.
*
* @param scandirPath the path originally passed to {@link #opendir(Object, Object)}
* @return an opaque object representing the dir entry path
* @see #getPathAsBytes(Object, Object)
* @see #getPathAsString(Object, Object)
*/
public abstract Object dirEntryGetPath(Object receiver, Object dirEntry, Object scandirPath) throws PosixException;
public abstract long dirEntryGetInode(Object receiver, Object dirEntry) throws PosixException;
/**
* @return one of the {@code DT_xxx} constants
*/
public abstract int dirEntryGetType(Object receiver, Object dirEntry);
/**
* Equivalent of POSIX {@code utimensat()}.
*
* @param timespec an array of 4 longs in this order:
* {@code atime.tv_sec, atime.tv_nsec, mtime.tv_sec, mtime.tv_nsec} or {@code null}
* to set both times to 'now' TODO change long[] timespec to Timespec[] timespec
*/
public abstract void utimensat(Object receiver, int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException;
/**
* Equivalent of POSIX {@code futimens()}.
*/
public abstract void futimens(Object receiver, int fd, long[] timespec) throws PosixException;
/**
* @param timeval either {@code null} or has two elements: access time and modification time
*/
public abstract void futimes(Object receiver, int fd, Timeval[] timeval) throws PosixException;
public abstract void lutimes(Object receiver, Object filename, Timeval[] timeval) throws PosixException;
public abstract void utimes(Object receiver, Object filename, Timeval[] timeval) throws PosixException;
public abstract void renameat(Object receiver, int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException;
public abstract boolean faccessat(Object receiver, int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks);
public abstract void fchmodat(Object receiver, int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException;
public abstract void fchmod(Object receiver, int fd, int mode) throws PosixException;
public abstract Object readlinkat(Object receiver, int dirFd, Object path) throws PosixException;
public abstract void kill(Object receiver, long pid, int signal) throws PosixException;
public abstract void killpg(Object receiver, long pid, int signal) throws PosixException;
public abstract long[] waitpid(Object receiver, long pid, int options) throws PosixException;
public abstract void abort(Object receiver);
public abstract boolean wcoredump(Object receiver, int status);
public abstract boolean wifcontinued(Object receiver, int status);
public abstract boolean wifstopped(Object receiver, int status);
public abstract boolean wifsignaled(Object receiver, int status);
public abstract boolean wifexited(Object receiver, int status);
public abstract int wexitstatus(Object receiver, int status);
public abstract int wtermsig(Object receiver, int status);
public abstract int wstopsig(Object receiver, int status);
public abstract long getuid(Object receiver);
public abstract long geteuid(Object receiver);
public abstract long getgid(Object receiver);
public abstract long getppid(Object receiver);
public abstract long getpgid(Object receiver, long pid) throws PosixException;
public abstract void setpgid(Object receiver, long pid, long pgid) throws PosixException;
public abstract long getpgrp(Object receiver);
public abstract long getsid(Object receiver, long pid) throws PosixException;
public abstract long setsid(Object receiver) throws PosixException;
public record OpenPtyResult(int masterFd, int slaveFd) {
}
public abstract OpenPtyResult openpty(Object receiver) throws PosixException;
public abstract TruffleString ctermid(Object receiver) throws PosixException;
// note: this leaks memory in nfi backend and is not synchronized
// TODO is it worth synchronizing at least all accesses made through PosixSupportLibrary?
public abstract void setenv(Object receiver, Object name, Object value, boolean overwrite) throws PosixException;
public abstract void unsetenv(Object receiver, Object name) throws PosixException;
public abstract int forkExec(Object receiver, Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd,
int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int[] fdsToKeep) throws PosixException;
// args.length must be > 0
public abstract void execv(Object receiver, Object pathname, Object[] args) throws PosixException;
// does not throw, because posix does not exactly define the return value
public abstract int system(Object receiver, Object command);
public abstract Object mmap(Object receiver, long length, int prot, int flags, int fd, long offset) throws PosixException;
public abstract byte mmapReadByte(Object receiver, Object mmap, long index) throws PosixException;
public abstract void mmapWriteByte(Object receiver, Object mmap, long index, byte value) throws PosixException;
public abstract int mmapReadBytes(Object receiver, Object mmap, long index, byte[] bytes, int length) throws PosixException;
public abstract void mmapWriteBytes(Object receiver, Object mmap, long index, byte[] bytes, int length) throws PosixException;
public abstract void mmapFlush(Object receiver, Object mmap, long offset, long length) throws PosixException;
public abstract void mmapUnmap(Object receiver, Object mmap, long length) throws PosixException;
public abstract long mmapGetPointer(Object receiver, Object mmap);
public static final class PwdResult {
public final TruffleString name;
/**
* This value represents unsigned 64 bit integer.
*/
public final long uid;
/**
* This value represents unsigned 64 bit integer.
*/
public final long gid;
public final TruffleString dir;
public final TruffleString shell;
public PwdResult(TruffleString name, long uid, long gid, TruffleString dir, TruffleString shell) {
this.name = name;
this.uid = uid;
this.gid = gid;
this.dir = dir;
this.shell = shell;
}
@Override
public String toString() {
return "PwdResult{name='" + name + '\'' +
", uid=" + uid +
", gid=" + gid +
", dir='" + dir + '\'' +
", shell='" + shell + "'}";
}
}
/**
* Equivalent of POSIX {@code getpwuid_r}. On top of the error codes defined by POSIX, this may
* also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found.
*/
public abstract PwdResult getpwuid(Object receiver, long uid) throws PosixException;
/**
* Equivalent of POSIX {@code getpwnam_r}. On top of the error codes defined by POSIX, this may
* also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found.
*
* @param receiver the receiver of the message
* @param name the name encoded the same way as paths
*/
public abstract PwdResult getpwnam(Object receiver, Object name) throws PosixException;
/**
* Availability of {@link #getpwentries(Object)}. If {@code false}, then
* {@link #getpwentries(Object)} will throw {@link UnsupportedPosixFeatureException}.
*/
public abstract boolean hasGetpwentries(Object receiver);
/**
* Returns a list of all entries in the password database. Equivalent of using POSIX functions
* {@code setpwent}, {@code getpwent}, and {@code endpwent}.
*/
public abstract PwdResult[] getpwentries(Object receiver) throws PosixException;
/**
* Converts a {@code TruffleString} into the internal representation of paths used by the
* library implementation. The implementation should return {@code null} if the path after any
* necessary conversion contains embedded null characters.
*
* @param receiver the receiver of the message
* @param path the path as a {@code TruffleString}
* @return an opaque object representing the path or {@code null} if the path contains null
* characters
*/
public abstract Object createPathFromString(Object receiver, TruffleString path);
/**
* Converts a {@code byte} array into the internal representation of paths used by the library
* implementation. The implementation should return {@code null} if the path after any necessary
* conversion contains embedded null characters.
*
* @param receiver the receiver of the message
* @param path the path as a a {@code byte[]} array
* @return an opaque object representing the path or {@code null} if the path contains null
* characters
*/
public abstract Object createPathFromBytes(Object receiver, byte[] path);
public abstract TruffleString getPathAsString(Object receiver, Object path);
public abstract Buffer getPathAsBytes(Object receiver, Object path);
// region Socket addresses
/**
* Base class for addresses specific to a particular socket family.
*
* The subclasses are simple POJOs whose definitions are common to all backends. They need to be
* converted to {@code UniversalSockAddr} before use.
*/
public abstract static class FamilySpecificSockAddr {
private final int family;
protected FamilySpecificSockAddr(int family) {
this.family = family;
}
public int getFamily() {
return family;
}
}
/**
* A tagged union of all address types which is capable of holding an address of any socket
* family.
*
* An universal socket address keeps the value in a representation used internally by the given
* backend, therefore implementations of this interface are backend-specific (unlike
* {@link FamilySpecificSockAddr} subclasses). This interface roughly corresponds to POSIX
* {@code struct sockaddr_storage}.
*
* @see UniversalSockAddrLibrary
*/
public interface UniversalSockAddr {
}
/**
* Represents an address for IPv4 sockets (the {@link PosixConstants#AF_INET} socket family).
*
* This is a higher level equivalent of POSIX {@code struct sockaddr_in} - integer values are
* kept in host byte order, conversion to network order ({@code htons/htonl}) is done
* automatically by the backend. This makes the integer representation of address compatible
* with the {@code INADDR_xxx} constants. On the other hand, addresses represented as byte
* arrays are in network order to make them compatible with {@code inet_pton} and
* {@code inet_ntop}).
*/
@ValueType
public static final class Inet4SockAddr extends FamilySpecificSockAddr {
private final int port; // host order, 0 - 65535
private final int address; // host order, e.g. INADDR_LOOPBACK
public Inet4SockAddr(int port, int address) {
super(AF_INET.value);
assert port >= 0 && port <= 65535;
this.port = port;
this.address = address;
}
public Inet4SockAddr(int port, byte[] address) {
this(port, bytesToInt(address));
}
public int getPort() {
return port;
}
public int getAddress() {
return address;
}
public byte[] getAddressAsBytes() {
return intToBytes(address);
}
private static int bytesToInt(byte[] src) {
assert src != null && src.length >= 4;
return ByteArraySupport.bigEndian().getInt(src, 0);
}
private static byte[] intToBytes(int src) {
byte[] dst = new byte[4];
ByteArraySupport.bigEndian().putInt(dst, 0, src);
return dst;
}
}
/**
* Represents an address for IPv6 sockets (the {@link PosixConstants#AF_INET6} socket family).
*
* This is a higher level equivalent of POSIX {@code struct sockaddr_in6} - the values are kept
* in host byte order, conversion to network order ({@code htons/htonl}) is done automatically
* by the backend.
*/
@ValueType
public static final class Inet6SockAddr extends FamilySpecificSockAddr {
private final int port; // host order, 0 - 65535
private final byte[] address = new byte[16];
private final int flowInfo; // host order, 0 - 2^20-1
private final int scopeId; // host order, interpreted as unsigned
public Inet6SockAddr(int port, byte[] address, int flowInfo, int scopeId) {
super(AF_INET6.value);
assert port >= 0 && port <= 65535;
assert address != null && address.length == 16;
assert flowInfo >= 0 && flowInfo <= 1048575;
this.port = port;
PythonUtils.arraycopy(address, 0, this.address, 0, 16);
this.flowInfo = flowInfo;
this.scopeId = scopeId;
}
public int getPort() {
return port;
}
public byte[] getAddress() {
return Arrays.copyOf(address, 16);
}
public int getFlowInfo() {
return flowInfo;
}
public int getScopeId() {
return scopeId;
}
}
/**
* Represents an address for UNIX domain sockets (the {@link PosixConstants#AF_UNIX} socket
* family).
*
* This is a higher level equivalent of POSIX {@code struct sockaddr_un}, see
* {@code man -7 unix}. It is the responsibility of the user to ensure that pathname addresses
* are zero terminated and abstract addresses start with a zero.
*/
@ValueType
public static final class UnixSockAddr extends FamilySpecificSockAddr {
private final byte[] path;
public UnixSockAddr(byte[] path) {
this(path, 0, path.length);
}
public UnixSockAddr(byte[] path, int offset, int length) {
super(AF_UNIX.value);
assert path != null && offset >= 0 && length >= 0 && length <= PosixConstants.SIZEOF_STRUCT_SOCKADDR_UN_SUN_PATH.value && offset + length <= path.length;
this.path = Arrays.copyOfRange(path, offset, offset + length);
}
/**
* Returns the path, which:
*
* - for unnamed addresses is of length 0,
* - for pathname addresses contains the terminating zero,
* - for abstract addresses start with a zero,
* - should not be modified by the caller.
*
*/
public byte[] getPath() {
return path;
}
}
// endregion
// region socket messages
/**
* Creates a new socket.
*
* @see "socket(2) man pages"
* @see PosixConstants
*/
public abstract int socket(Object receiver, int domain, int type, int protocol) throws PosixException;
public abstract AcceptResult accept(Object receiver, int sockfd) throws PosixException;
public abstract void bind(Object receiver, int sockfd, UniversalSockAddr addr) throws PosixException;
public abstract void connect(Object receiver, int sockfd, UniversalSockAddr addr) throws PosixException;
public abstract void listen(Object receiver, int sockfd, int backlog) throws PosixException;
public abstract UniversalSockAddr getpeername(Object receiver, int sockfd) throws PosixException;
public abstract UniversalSockAddr getsockname(Object receiver, int sockfd) throws PosixException;
public abstract int send(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException;
// Unlike POSIX sendto(), we don't support destAddr == null. Use plain send instead.
public abstract int sendto(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException;
public abstract int recv(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException;
// For STREAM sockets, the returned address will be AF_UNSPEC
public abstract RecvfromResult recvfrom(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException;
public static final class AcceptResult {
public final int socketFd;
public final UniversalSockAddr sockAddr;
public AcceptResult(int socketFd, UniversalSockAddr sockAddr) {
this.socketFd = socketFd;
this.sockAddr = sockAddr;
}
@Override
public String toString() {
CompilerAsserts.neverPartOfCompilation();
return "RecvfromResult{" + "socketFd=" + socketFd + ", sockAddr=" + sockAddr + '}';
}
}
public static final class RecvfromResult {
public final int readBytes;
public final UniversalSockAddr sockAddr;
public RecvfromResult(int readBytes, UniversalSockAddr sockAddr) {
this.readBytes = readBytes;
this.sockAddr = sockAddr;
}
@Override
public String toString() {
CompilerAsserts.neverPartOfCompilation();
return "RecvfromResult{" + "readBytes=" + readBytes + ", sockAddr=" + sockAddr + '}';
}
}
public abstract void shutdown(Object receiver, int sockfd, int how) throws PosixException;
/**
* @param optval buffer for the option value
* @param optlen size of the buffer // TODO use optval.length instead? See also recv,
* mmapReadBytes, read and GR-29856
* @return the actual size of the value returned
*/
public abstract int getsockopt(Object receiver, int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException;
public abstract void setsockopt(Object receiver, int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException;
// endregion
// region Name resolution messages
/**
* Corresponds to POSIX {@code inet_addr} function, but the address is returned in host byte
* order (and is signed) so that it can be used in {@link Inet4SockAddr} directly without any
* further conversions. If the input is invalid, the native function returns
* {@link PosixConstants#INADDR_NONE}, which is also returned when the input is
* {@code 255.255.255.255}. Since it is not possible to tell whether an error occurred, this
* message does not throw exception and leaves the decision to the caller who might have more
* information.
*
* @param src the IPv4 address in numbers-and-dots notation (converted to opaque object using
* createPathFromBytes or createPathFromString)
* @return address in host byte order or {@link PosixConstants#INADDR_NONE} if the input is
* invalid
* @see "inet(3) man pages"
*/
public abstract int inet_addr(Object receiver, Object src);
/**
* Corresponds to POSIX {@code inet_aton} function, but the address is returned in host byte
* order (and is signed) so that it can be used in {@link Inet4SockAddr} directly without any
* further conversions.
*
* @param src the IPv4 address in numbers-and-dots notation (converted to opaque object using
* createPathFromBytes or createPathFromString)
* @return address in host byte order
* @throws InvalidAddressException if {@code cp} is not a valid representation of an IPv4
* address
* @see "inet(3) man pages"
*/
public abstract int inet_aton(Object receiver, Object src) throws InvalidAddressException;
/**
* Corresponds to POSIX {@code inet_ntoa} function, but the address is expected in host byte
* order (and is signed) for consistency with other messages.
*
* @param address tha IPv4 address in host byte order
* @return opaque string in IPv4 dotted-decimal notation to be converted using
* {@link PosixSupportLibrary#getPathAsString(Object, Object)} or
* {@link PosixSupportLibrary#getPathAsBytes(Object, Object)}
* @see "inet(3) man pages"
*/
public abstract Object inet_ntoa(Object receiver, int address);
/**
* Corresponds to POSIX {@code inet_pton} function.
*
* @param family {@code AF_INET} or {@code AF_INET6}
* @param src opaque string (converted using createPathFromBytes or createPathFromString)
* @return the binary address in network order (4 bytes for {@code AF_INET}, 16 bytes for
* {@code AF_INET6})
* @throws PosixException with {@code EAFNOSUPPORT} if the {@code family} is not supported
* @throws InvalidAddressException if {@code src} is not a valid representation of an address of
* given family
*/
public abstract byte[] inet_pton(Object receiver, int family, Object src) throws PosixException, InvalidAddressException;
/**
* Corresponds to POSIX {@code inet_ntop} function.
*
* @param family {@code AF_INET} or {@code AF_INET6}
* @param src the address in network order, must be at least 4 (for {@code AF_INET}) or 16 (for
* {@code AF_INET6}) bytes long, extra bytes are ignored
* @return an opaque string to be converted using getPathAsString or getPathAsBytes
* @throws PosixException with {@code EAFNOSUPPORT} if the {@code family} is not supported
* @throws IllegalArgumentException if {@code src} does not satisfy the requirements stated
* above
*/
public abstract Object inet_ntop(Object receiver, int family, byte[] src) throws PosixException;
/**
* @return an opaque string to be converted using getPathAsString or getPathAsBytes
*/
public abstract Object gethostname(Object receiver) throws PosixException;
/**
* Corresponds to POSIX {@code getnameinfo(3)}, except it always retrieves both host and service
* names.
*
* @param addr socket address to convert
* @param flags a combination of {@code NI_xxx} flags
* @return an array of two (host, service) opaque strings to be converted using getPathAsString
* or getPathAsBytes
* @throws GetAddrInfoException when an error occurs (PosixException is not thrown because
* getnameinfo uses its own error codes and gai_strerror instead of the usual errno
* and strerror)
*/
public abstract Object[] getnameinfo(Object receiver, UniversalSockAddr addr, int flags) throws GetAddrInfoException;
/**
* Corresponds to POSIX {@code getaddrinfo(3)}, except it always passes a non-null value for the
* {@code hints} parameter.
*
* @param node {@code null} or the host name converted using
* {@link PosixSupportLibrary#createPathFromBytes(Object, byte[])} or
* {@link PosixSupportLibrary#createPathFromString(Object, TruffleString)}
* @param service {@code null} or the service name converted using
* {@link PosixSupportLibrary#createPathFromBytes(Object, byte[])} or
* {@link PosixSupportLibrary#createPathFromString(Object, TruffleString)}
* @param family one of the {@code AF_xxx} constants, or {@link PosixConstants#AF_UNSPEC} to get
* addresses of any family
* @param sockType one of the {@code SOCK_xxx} constants, or 0 to get addresses of any type
* @param protocol 0 to get addresses with any protocol
* @param flags bitwise OR of {@code AI_xxx} constants
* @return an object representing one or more {@code struct addrinfo}s, which must be explicitly
* released by the caller
* @throws GetAddrInfoException when an error occurs (PosixException is not thrown because
* getaddrinfo uses its own error codes and gai_strerror instead of the usual errno
* and strerror)
*/
public abstract AddrInfoCursor getaddrinfo(Object receiver, Object node, Object service, int family, int sockType, int protocol, int flags) throws GetAddrInfoException;
/**
* Represents one or more addrinfos returned by {@code getaddrinfo()}.
*
* Must be explicitly released using {@link AddrInfoCursorLibrary#release(AddrInfoCursor)}.
* Behaves like a cursor which points to a {@code struct addrinfo} structure (initially pointing
* at the first address info). The cursor can only move forward using the
* {@link AddrInfoCursorLibrary#next(AddrInfoCursor)} message.
*
* @see AddrInfoCursorLibrary
*/
public interface AddrInfoCursor {
}
/**
* Corresponds to POSIX crypt function that hashes passwords with salt.
*
* @param word password to be hashed
* @param salt random salt, optionally prefixed with $DIGIT$ hash method indication
* @return hashed password
* @throws PosixException when an error occurs in the underlying crypt call
* @see "crypt(3) manpage"
*/
public abstract TruffleString crypt(Object receiver, TruffleString word, TruffleString salt) throws PosixException;
/**
* Provides messages for manipulating {@link AddrInfoCursor}.
*/
@GenerateLibrary
public abstract static class AddrInfoCursorLibrary extends Library {
protected AddrInfoCursorLibrary() {
}
/**
* Releases resources associated with the results of {@code getaddrinfo()}.
*
* This must be called exactly once on all instances returned from
* {@link #getaddrinfo(Object, Object, Object, int, int, int, int)}. Released instances can
* no longer be used for any purpose.
*/
public abstract void release(AddrInfoCursor receiver);
/**
* Moves the cursor to the next address info.
*
* @return false if there are no more address infos in which case the cursor keeps pointing
* to the last item
*/
public abstract boolean next(AddrInfoCursor receiver);
public abstract int getFlags(AddrInfoCursor receiver);
public abstract int getFamily(AddrInfoCursor receiver);
public abstract int getSockType(AddrInfoCursor receiver);
public abstract int getProtocol(AddrInfoCursor receiver);
/**
* @return {@code null} or opaque name to be converted using
* {@link PosixSupportLibrary#getPathAsString(Object, Object)} or
* {@link PosixSupportLibrary#getPathAsBytes(Object, Object)}
*/
public abstract Object getCanonName(AddrInfoCursor receiver);
public abstract UniversalSockAddr getSockAddr(AddrInfoCursor receiver);
static final LibraryFactory FACTORY = LibraryFactory.resolve(AddrInfoCursorLibrary.class);
public static LibraryFactory getFactory() {
return FACTORY;
}
public static AddrInfoCursorLibrary getUncached() {
return FACTORY.getUncached();
}
}
/**
* Exception that indicates and error while executing
* {@link #getaddrinfo(Object, Object, Object, int, int, int, int)}.
*/
public static class GetAddrInfoException extends Exception {
private static final long serialVersionUID = 3013253817849329391L;
private final int errorCode;
private final transient TruffleString msg;
public GetAddrInfoException(int errorCode, TruffleString message) {
super(message.toJavaStringUncached());
this.errorCode = errorCode;
msg = message;
}
public int getErrorCode() {
return errorCode;
}
public final TruffleString getMessageAsTruffleString() {
return msg;
}
@SuppressWarnings("sync-override")
@Override
public final Throwable fillInStackTrace() {
return this;
}
}
// endregion
/**
* Allocates a new {@link UniversalSockAddr} and initializes it with the provided address.
*/
public abstract UniversalSockAddr createUniversalSockAddr(Object receiver, FamilySpecificSockAddr src);
/**
* Provides messages for manipulating {@link UniversalSockAddr}.
*/
@GenerateLibrary
public abstract static class UniversalSockAddrLibrary extends Library {
protected UniversalSockAddrLibrary() {
}
/**
* Returns the socket family of the address (one of the {@code AF_xxx} values defined in
* {@link PosixConstants}).
*/
public abstract int getFamily(UniversalSockAddr receiver);
/**
* Converts the address represented by the receiver (which must be of the
* {@link PosixConstants#AF_INET} family) into a {@link Inet4SockAddr} instance.
*
* @throws IllegalArgumentException if the socket family of the address is not
* {@link PosixConstants#AF_INET}
*/
public abstract Inet4SockAddr asInet4SockAddr(UniversalSockAddr receiver);
/**
* Converts the address represented by the receiver (which must be of the
* {@link PosixConstants#AF_INET6} family) into a {@link Inet6SockAddr} instance.
*
* @throws IllegalArgumentException if the socket family of the address is not
* {@link PosixConstants#AF_INET6}
*/
public abstract Inet6SockAddr asInet6SockAddr(UniversalSockAddr receiver);
/**
* Converts the address represented by the receiver (which must be of the
* {@link PosixConstants#AF_UNIX} family) into a {@link UnixSockAddr} instance.
*
* @throws IllegalArgumentException if the socket family of the address is not
* {@link PosixConstants#AF_UNIX}
*/
public abstract UnixSockAddr asUnixSockAddr(UniversalSockAddr receiver);
static final LibraryFactory FACTORY = LibraryFactory.resolve(UniversalSockAddrLibrary.class);
public static LibraryFactory getFactory() {
return FACTORY;
}
public static UniversalSockAddrLibrary getUncached() {
return FACTORY.getUncached();
}
}
/**
* Exception that indicates POSIX level error associated with numeric code. If the message is
* known, it may be included in the exception, otherwise it can be queried using
* {@link #strerror(Object, int)}.
*/
public static final class PosixException extends Exception {
private static final long serialVersionUID = -115762483478883093L;
private final int errorCode;
private final transient TruffleString msg;
public PosixException(int errorCode, TruffleString message) {
this.errorCode = errorCode;
msg = message;
}
public final TruffleString getMessageAsTruffleString() {
return msg;
}
@Override
public String getMessage() {
return msg.toJavaStringUncached();
}
public int getErrorCode() {
return errorCode;
}
@SuppressWarnings("sync-override")
@Override
public final Throwable fillInStackTrace() {
return this;
}
}
/**
* Exception that indicates that a string of characters passed into the {@code inet_aton} or
* {@code inet_pton} function does not represent a valid IP address. These functions do not use
* the usual {@code errno} mechanism to report this kind of errors.
*/
public static class InvalidAddressException extends Exception {
private static final long serialVersionUID = -2999913421191382026L;
public InvalidAddressException() {
}
@SuppressWarnings("sync-override")
@Override
public final Throwable fillInStackTrace() {
return this;
}
}
/**
* Exception that may be thrown by all the messages. It indicates that given functionality is
* not available in given implementation. In the future, there will be methods to query if
* certain feature is supported or not, but even then this exception may be thrown for other
* features.
*/
public static class UnsupportedPosixFeatureException extends RuntimeException {
private static final long serialVersionUID = 1846254827094902593L;
public UnsupportedPosixFeatureException(String message) {
super(message);
}
@Override
@SuppressWarnings("sync-override")
public final Throwable fillInStackTrace() {
return this;
}
}
/**
* Simple wrapper that allows exchanging byte buffers with the outside world.
*/
@ValueType
public static class Buffer {
public final byte[] data;
public long length;
public Buffer(byte[] data, long length) {
assert data != null && length >= 0 && length <= data.length;
this.data = data;
this.length = length;
}
public static Buffer allocate(long capacity) {
if (capacity > Integer.MAX_VALUE) {
throw CompilerDirectives.shouldNotReachHere("Long arrays are not supported yet");
}
return new Buffer(new byte[(int) capacity], 0);
}
public static Buffer wrap(byte[] data) {
return new Buffer(data, data.length);
}
public Buffer withLength(long newLength) {
if (newLength > data.length) {
throw CompilerDirectives.shouldNotReachHere("Actual length cannot be greater than capacity");
}
length = newLength;
return this;
}
@TruffleBoundary
public ByteBuffer getByteBuffer() {
return ByteBuffer.wrap(data, 0, (int) length);
}
}
/**
* Corresponds to the {@code timeval} struct.
*/
@ValueType
public static final class Timeval {
public static final Timeval SELECT_TIMEOUT_NOW = new Timeval(0, 0);
private final long seconds;
private final long microseconds;
public Timeval(long seconds, long microseconds) {
this.seconds = seconds;
this.microseconds = microseconds;
}
public long getSeconds() {
return seconds;
}
public long getMicroseconds() {
return microseconds;
}
}
/**
* Wraps boolean arrays that indicate if given file descriptor was selected or not. For example,
* if {@code getReadFds()[X]} is {@code true}, then the file descriptor that was passed to
* {@code select} as {@code readfds[X]} was selected.
*/
@ValueType
public static final class SelectResult {
private final boolean[] readfds;
private final boolean[] writefds;
private final boolean[] errorfds;
public SelectResult(boolean[] readfds, boolean[] writefds, boolean[] errorfds) {
this.readfds = readfds;
this.writefds = writefds;
this.errorfds = errorfds;
}
public boolean[] getReadFds() {
return readfds;
}
public boolean[] getWriteFds() {
return writefds;
}
public boolean[] getErrorFds() {
return errorfds;
}
@Override
public String toString() {
CompilerAsserts.neverPartOfCompilation();
return String.format("select[read = %s; write = %s; err = %s]", Arrays.toString(readfds), Arrays.toString(writefds), Arrays.toString(errorfds));
}
}
// from stat.h macros
private static boolean istype(long mode, int mask) {
return (mode & S_IFMT.value) == mask;
}
public static boolean isDIR(long mode) {
return istype(mode, S_IFDIR.value);
}
public static boolean isCHR(long mode) {
return istype(mode, S_IFCHR.value);
}
public static boolean isBLK(long mode) {
return istype(mode, S_IFBLK.value);
}
public static boolean isREG(long mode) {
return istype(mode, S_IFREG.value);
}
public static boolean isFIFO(long mode) {
return istype(mode, S_IFIFO.value);
}
public static boolean isLNK(long mode) {
return istype(mode, S_IFLNK.value);
}
public static class ChannelNotSelectableException extends UnsupportedPosixFeatureException {
private static final long serialVersionUID = -4185480181939639297L;
static ChannelNotSelectableException INSTANCE = new ChannelNotSelectableException();
private ChannelNotSelectableException() {
super(null);
}
}
static final LibraryFactory FACTORY = LibraryFactory.resolve(PosixSupportLibrary.class);
public static LibraryFactory getFactory() {
return FACTORY;
}
public static PosixSupportLibrary getUncached() {
return FACTORY.getUncached();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy