Module rsyscall.sys.socket
#include <sys/socket.h>
Expand source code Browse git
"`#include <sys/socket.h>`"
from __future__ import annotations
from rsyscall._raw import ffi, lib # type: ignore
from dataclasses import dataclass
import typing as t
import enum
from rsyscall.struct import Struct, FixedSerializer, Serializable, Serializer, HasSerializer, FixedSize
import contextlib
import abc
import struct
import rsyscall.near.types as near
from rsyscall.handle.pointer import Pointer, WrittenPointer, ReadablePointer, LinearPointer
if t.TYPE_CHECKING:
from rsyscall.handle import FileDescriptor, Task
else:
FileDescriptor = object
from rsyscall.sys.uio import IovecList
__all__ = [
"AF",
"SHUT",
"Sockaddr",
"SockaddrStorage",
"SOCK",
"SOL",
"SO",
"MSG",
"Socketpair",
"Sockbuf",
"CmsgSCMRights",
"CmsgList",
"SendMsghdr",
"RecvMsghdr",
"RecvMsghdrOut",
"SendmsgFlags",
"RecvmsgFlags",
"MsghdrFlags",
"SocketTask",
"SocketFileDescriptor",
]
T = t.TypeVar('T')
class AF(enum.IntEnum):
UNIX = lib.AF_UNIX
NETLINK = lib.AF_NETLINK
INET = lib.AF_INET
INET6 = lib.AF_INET6
class SHUT(enum.IntEnum):
RD = lib.SHUT_RD
WR = lib.SHUT_WR
RDWR = lib.SHUT_RDWR
class MSG(enum.IntFlag):
NONE = 0
# send flags
CONFIRM = lib.MSG_CONFIRM
DONTROUTE = lib.MSG_DONTROUTE
EOR = lib.MSG_EOR
MORE = lib.MSG_MORE
NOSIGNAL = lib.MSG_NOSIGNAL
# recv flags
CMSG_CLOEXEC = lib.MSG_CMSG_CLOEXEC
ERRQUEUE = lib.MSG_ERRQUEUE
PEEK = lib.MSG_PEEK
TRUNC = lib.MSG_TRUNC
WAITALL = lib.MSG_WAITALL
# both
DONTWAIT = lib.MSG_DONTWAIT
OOB = lib.MSG_OOB
family_to_class: t.Dict[AF, t.Type[Sockaddr]] = {}
def _register_sockaddr(sockaddr: t.Type[Sockaddr]) -> None:
if sockaddr.family in family_to_class:
raise Exception("tried to register sockaddr", sockaddr, "for family", sockaddr.family,
"but there's already a class registered for that family:",
family_to_class[sockaddr.family])
family_to_class[sockaddr.family] = sockaddr
class Sockaddr(Struct):
"""struct sockaddr. This is not really useful to allocate on its own; you want the derived classes.
"""
def __init__(self, family: AF, data: bytes) -> None:
self.family = family
self.data = data
@classmethod
def check_family(cls, family: AF) -> None:
if cls.family != family:
raise Exception("sa_family should be", cls.family, "is instead", family)
def to_bytes(self) -> bytes:
struct = ffi.new('struct sockaddr*', (self.family, self.data))
return bytes(ffi.buffer(struct))
T = t.TypeVar('T', bound='Sockaddr')
@classmethod
def from_bytes(cls: t.Type[T], data: bytes) -> T:
struct = ffi.cast('struct sockaddr*', ffi.from_buffer(data))
return cls(struct.sa_family, bytes(ffi.buffer(struct.sa_data)))
@classmethod
def sizeof(cls) -> int:
return ffi.sizeof('struct sockaddr')
def parse(self) -> Sockaddr:
"Using the family field, return the correct Sockaddr type that this actually contains."
cls = family_to_class[self.family]
return cls.from_bytes(self.to_bytes())
T_sockaddr = t.TypeVar('T_sockaddr', bound='Sockaddr')
class SOCK(enum.IntFlag):
NONE = 0
# socket kinds
DGRAM = lib.SOCK_DGRAM
STREAM = lib.SOCK_STREAM
SEQPACKET = lib.SOCK_SEQPACKET
RAW = lib.SOCK_RAW
# flags that can be or'd in
CLOEXEC = lib.SOCK_CLOEXEC
NONBLOCK = lib.SOCK_NONBLOCK
class SOL(enum.IntEnum):
"""Stands for Sock Opt Level
This is what should be passed as the "level" argument to
getsockopt/setsockopt.
"""
SOCKET = lib.SOL_SOCKET
IP = lib.SOL_IP
class SO(enum.IntEnum):
ACCEPTCONN = lib.SO_ACCEPTCONN
ATTACH_FILTER = lib.SO_ATTACH_FILTER
ATTACH_BPF = lib.SO_ATTACH_BPF
ATTACH_REUSEPORT_CBPF = lib.SO_ATTACH_REUSEPORT_CBPF
ATTACH_REUSEPORT_EBPF = lib.SO_ATTACH_REUSEPORT_EBPF
BINDTODEVICE = lib.SO_BINDTODEVICE
BROADCAST = lib.SO_BROADCAST
BSDCOMPAT = lib.SO_BSDCOMPAT
DEBUG = lib.SO_DEBUG
DETACH_FILTER = lib.SO_DETACH_FILTER
DETACH_BPF = lib.SO_DETACH_BPF
DOMAIN = lib.SO_DOMAIN
ERROR = lib.SO_ERROR
DONTROUTE = lib.SO_DONTROUTE
INCOMING_CPU = lib.SO_INCOMING_CPU
KEEPALIVE = lib.SO_KEEPALIVE
LINGER = lib.SO_LINGER
LOCK_FILTER = lib.SO_LOCK_FILTER
MARK = lib.SO_MARK
OOBINLINE = lib.SO_OOBINLINE
PASSCRED = lib.SO_PASSCRED
PEEK_OFF = lib.SO_PEEK_OFF
PEERCRED = lib.SO_PEERCRED
PRIORITY = lib.SO_PRIORITY
PROTOCOL = lib.SO_PROTOCOL
RCVBUF = lib.SO_RCVBUF
RCVBUFFORCE = lib.SO_RCVBUFFORCE
RCVLOWAT = lib.SO_RCVLOWAT
SNDLOWAT = lib.SO_SNDLOWAT
RCVTIMEO = lib.SO_RCVTIMEO
SNDTIMEO = lib.SO_SNDTIMEO
REUSEADDR = lib.SO_REUSEADDR
REUSEPORT = lib.SO_REUSEPORT
RXQ_OVFL = lib.SO_RXQ_OVFL
SNDBUF = lib.SO_SNDBUF
SNDBUFFORCE = lib.SO_SNDBUFFORCE
TIMESTAMP = lib.SO_TIMESTAMP
TYPE = lib.SO_TYPE
BUSY_POLL = lib.SO_BUSY_POLL
class SCM(enum.IntEnum):
RIGHTS = lib.SCM_RIGHTS
@dataclass
class SockaddrStorage(Sockaddr):
"struct sockaddr_storage. Useful when dealing with sockets with unknown address families"
family: AF
data: bytes
def to_bytes(self) -> bytes:
# We can't just create a struct sockaddr_storage and turn the whole thing to bytes,
# because that will pad the actually valid data with a bunch of trailing null bytes.
# And we can't do that because the length of the valid data is semantically
# meaningful for some socket addresses, such as sockaddr_un.
return bytes(ffi.buffer(ffi.new('sa_family_t*', self.family))) + self.data
T = t.TypeVar('T', bound='SockaddrStorage')
@classmethod
def from_bytes(cls: t.Type[T], data: bytes) -> T:
# As with to_bytes, we can't just cast the bytes to a struct sockaddr_storage and read its data field,
# because that would pad the data with a bunch of null bytes,
# and would not preserve the length of the valid data
family = ffi.cast('sa_family_t*', ffi.from_buffer(data))
rest = data[ffi.sizeof('sa_family_t'):]
return cls(
family=AF(family[0]),
data=rest
)
@classmethod
def sizeof(cls) -> int:
return ffi.sizeof('struct sockaddr_storage')
@dataclass
class Sockbuf(t.Generic[T], HasSerializer):
buf: Pointer[T]
buf_rest: t.Optional[Pointer[T]] = None
def get_self_serializer(self, task: Task) -> SockbufSerializer[T]:
return SockbufSerializer(self.buf)
class SockbufSerializer(t.Generic[T], Serializer[Sockbuf[T]]):
def __init__(self, buf: Pointer[T]) -> None:
self.buf = buf
def to_bytes(self, val: Sockbuf) -> bytes:
return bytes(ffi.buffer(ffi.new('socklen_t*', val.buf.size())))
def from_bytes(self, data: bytes) -> Sockbuf[T]:
struct = ffi.cast('socklen_t*', ffi.from_buffer(data))
socklen = struct[0]
if socklen > self.buf.size():
raise Exception("not enough buffer space to read socket, need", socklen)
valid, rest = self.buf.readable_split(socklen)
return Sockbuf(valid, rest)
#### socketpair stuff
T_socketpair = t.TypeVar('T_socketpair', bound='Socketpair')
@dataclass
class Socketpair(FixedSize):
first: FileDescriptor
second: FileDescriptor
@classmethod
def sizeof(cls) -> int:
return ffi.sizeof('struct fdpair')
@classmethod
def get_serializer(cls: t.Type[T_socketpair], task: Task) -> Serializer[T_socketpair]:
return SocketpairSerializer(cls, task)
@dataclass
class SocketpairSerializer(Serializer[T_socketpair]):
cls: t.Type[T_socketpair]
task: Task
def to_bytes(self, pair: T_socketpair) -> bytes:
struct = ffi.new('struct fdpair*', (pair.first, pair.second))
return bytes(ffi.buffer(struct))
def from_bytes(self, data: bytes) -> T_socketpair:
struct = ffi.cast('struct fdpair const*', ffi.from_buffer(data))
def make(n: int) -> FileDescriptor:
return self.task.make_fd_handle(near.FileDescriptor(int(n)))
return self.cls(make(struct.first), make(struct.second))
#### sendmsg/recvmsg stuff
class SendmsgFlags(enum.IntFlag):
NONE = 0
class RecvmsgFlags(enum.IntFlag):
NONE = 0
CMSG_CLOEXEC = lib.MSG_CMSG_CLOEXEC
class MsghdrFlags(enum.IntFlag):
NONE = 0
CTRUNC = lib.MSG_CTRUNC
CMSG_CLOEXEC = lib.MSG_CMSG_CLOEXEC
T_cmsg = t.TypeVar('T_cmsg', bound='Cmsg')
class Cmsg(FixedSerializer):
@abc.abstractmethod
def to_data(self) -> bytes: ...
@abc.abstractmethod
def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) -> None: ...
@classmethod
@abc.abstractmethod
def from_data(cls: t.Type[T], task: Task, data: bytes) -> T: ...
@classmethod
@abc.abstractmethod
def level(cls: t.Type[T]) -> SOL: ...
@classmethod
@abc.abstractmethod
def type(cls: t.Type[T]) -> int: ...
@classmethod
def get_serializer(cls: t.Type[T_cmsg], task: Task) -> Serializer[T_cmsg]:
return CmsgSerializer(cls, task)
class CmsgSerializer(Serializer[T_cmsg]):
def __init__(self, cls: t.Type[T_cmsg], task: Task) -> None:
self.cls = cls
self.task = task
def to_bytes(self, val: T_cmsg) -> bytes:
if not isinstance(val, self.cls):
raise Exception("Serializer for", self.cls,
"had to_bytes called on different type", val)
data = val.to_data()
header = bytes(ffi.buffer(ffi.new('struct cmsghdr*', {
"cmsg_len": ffi.sizeof('struct cmsghdr') + len(data),
"cmsg_level": val.level(),
"cmsg_type": val.type(),
})))
return header + data
def from_bytes(self, data: bytes) -> T_cmsg:
record = ffi.cast('struct cmsghdr*', ffi.from_buffer(data))
if record.cmsg_level != self.cls.level():
raise Exception("serializer for level", self.cls.level(),
"got message for level", record.cmsg_level)
if record.cmsg_type != self.cls.type():
raise Exception("serializer for type", self.cls.type(),
"got message for type", record.cmsg_type)
return self.cls.from_data(self.task, data[ffi.sizeof('struct cmsghdr'):record.cmsg_len])
import array
class CmsgSCMRights(Cmsg, t.List[FileDescriptor]):
def to_data(self) -> bytes:
return array.array('i', (int(fd) for fd in self)).tobytes()
def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) -> None:
for fd in self:
stack.enter_context(fd.borrow(task))
T = t.TypeVar('T', bound='CmsgSCMRights')
@classmethod
def from_data(cls: t.Type[T], task: Task, data: bytes) -> T:
fds = [near.FileDescriptor(fd) for fd, in struct.Struct('i').iter_unpack(data)]
return cls([task.make_fd_handle(fd) for fd in fds])
@classmethod
def level(cls) -> SOL:
return SOL.SOCKET
@classmethod
def type(cls) -> int:
return SCM.RIGHTS
T_cmsglist = t.TypeVar('T_cmsglist', bound='CmsgList')
class CmsgList(t.List[Cmsg], FixedSerializer):
@classmethod
def get_serializer(cls: t.Type[T_cmsglist], task: Task) -> Serializer[T_cmsglist]:
return CmsgListSerializer(cls, task)
def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) -> None:
for cmsg in self:
cmsg.borrow_with(stack, task)
class CmsgListSerializer(Serializer[T_cmsglist]):
def __init__(self, cls: t.Type[T_cmsglist], task: Task) -> None:
self.cls = cls
self.task = task
def to_bytes(self, val: T_cmsglist) -> bytes:
ret = b""
for cmsg in val:
# TODO is this correct alignment/padding???
# I don't think so...
ret += cmsg.get_serializer(self.task).to_bytes(cmsg)
return ret
def from_bytes(self, data: bytes) -> T_cmsglist:
entries = []
while len(data) > 0:
record = ffi.cast('struct cmsghdr*', ffi.from_buffer(data))
record_data = data[:record.cmsg_len]
level = SOL(record.cmsg_level)
if level == SOL.SOCKET and record.cmsg_type == int(SCM.RIGHTS):
entries.append(CmsgSCMRights.get_serializer(self.task).from_bytes(record_data))
else:
raise Exception("unknown cmsg level/type sorry", level, type)
data = data[record.cmsg_len:]
return self.cls(entries)
@dataclass
class SendMsghdr(Serializable):
name: t.Optional[WrittenPointer[Sockaddr]]
iov: WrittenPointer[IovecList]
control: t.Optional[WrittenPointer[CmsgList]]
def to_bytes(self) -> bytes:
return bytes(ffi.buffer(ffi.new('struct msghdr*', {
"msg_name": ffi.cast('void*', int(self.name.near)) if self.name else ffi.NULL,
"msg_namelen": self.name.size() if self.name else 0,
"msg_iov": ffi.cast('void*', int(self.iov.near)),
"msg_iovlen": len(self.iov.value),
"msg_control": ffi.cast('void*', int(self.control.near)) if self.control else ffi.NULL,
"msg_controllen": self.control.size() if self.control else 0,
"msg_flags": 0,
})))
T = t.TypeVar('T', bound='SendMsghdr')
@classmethod
def from_bytes(cls: t.Type[T], data: bytes) -> T:
raise Exception("can't get pointer handles from raw bytes")
@dataclass
class RecvMsghdr(Serializable):
name: t.Optional[Pointer[Sockaddr]]
iov: WrittenPointer[IovecList]
control: t.Optional[Pointer[CmsgList]]
def to_bytes(self) -> bytes:
return bytes(ffi.buffer(ffi.new('struct msghdr*', {
"msg_name": ffi.cast('void*', int(self.name.near)) if self.name else ffi.NULL,
"msg_namelen": self.name.size() if self.name else 0,
"msg_iov": ffi.cast('void*', int(self.iov.near)),
"msg_iovlen": len(self.iov.value),
"msg_control": ffi.cast('void*', int(self.control.near)) if self.control else ffi.NULL,
"msg_controllen": self.control.size() if self.control else 0,
"msg_flags": 0,
})))
T = t.TypeVar('T', bound='RecvMsghdr')
@classmethod
def from_bytes(cls: t.Type[T], data: bytes) -> T:
raise Exception("can't get pointer handles from raw bytes")
def to_out(self, ptr: Pointer[RecvMsghdr]) -> Pointer[RecvMsghdrOut]:
# what a mouthful
serializer = RecvMsghdrOutSerializer(self.name, self.control)
return ptr._reinterpret(serializer, RecvMsghdrOut)
@dataclass
class RecvMsghdrOut:
name: t.Optional[ReadablePointer[Sockaddr]]
control: t.Optional[LinearPointer[CmsgList]]
flags: MsghdrFlags
# the _rest fields are the invalid, unused parts of the buffers;
# almost everyone can ignore these.
name_rest: t.Optional[Pointer[Sockaddr]]
control_rest: t.Optional[Pointer[CmsgList]]
@dataclass
class RecvMsghdrOutSerializer(Serializer[RecvMsghdrOut]):
name: t.Optional[Pointer[Sockaddr]]
control: t.Optional[Pointer[CmsgList]]
def to_bytes(self, x: RecvMsghdrOut) -> bytes:
raise Exception("not going to bother implementing this")
def from_bytes(self, data: bytes) -> RecvMsghdrOut:
struct = ffi.cast('struct msghdr*', ffi.from_buffer(data))
if self.name is None:
name: t.Optional[ReadablePointer[Sockaddr]] = None
name_rest: t.Optional[Pointer[Sockaddr]] = None
else:
name, name_rest = self.name.readable_split(struct.msg_namelen)
if self.control is None:
control: t.Optional[Pointer[CmsgList]] = None
control_rest: t.Optional[Pointer[CmsgList]] = None
else:
control, control_rest = self.control.readable_split(struct.msg_controllen)
flags = MsghdrFlags(struct.msg_flags)
return RecvMsghdrOut(name, control._linearize() if control else None, flags, name_rest, control_rest)
#### Classes ####
from rsyscall.handle.fd import BaseFileDescriptor, FileDescriptorTask
T_fd = t.TypeVar('T_fd', bound='SocketFileDescriptor')
class SocketFileDescriptor(BaseFileDescriptor):
async def bind(self, addr: WrittenPointer[Sockaddr]) -> None:
"""bind a name to a socket
man: bind(2)
"""
self._validate()
with addr.borrow(self.task):
try:
await _bind(self.task.sysif, self.near, addr.near, addr.size())
except PermissionError as exn:
exn.filename = addr.value
raise
except FileNotFoundError as exn:
exn.filename = addr.value
raise
async def connect(self, addr: WrittenPointer[Sockaddr]) -> None:
self._validate()
with addr.borrow(self.task):
try:
await _connect(self.task.sysif, self.near, addr.near, addr.size())
except OSError as exn:
exn.filename = self
if hasattr(addr, 'value'):
exn.filename2 = addr.value
raise
async def listen(self, backlog: int) -> None:
self._validate()
await _listen(self.task.sysif, self.near, backlog)
async def getsockopt(self, level: int, optname: int, optval: WrittenPointer[Sockbuf[T]]) -> Pointer[Sockbuf[T]]:
self._validate()
with optval.borrow(self.task):
with optval.value.buf.borrow(self.task):
await _getsockopt(self.task.sysif, self.near,
level, optname, optval.value.buf.near, optval.near)
return optval
async def setsockopt(self, level: int, optname: int, optval: Pointer) -> None:
self._validate()
with optval.borrow(self.task) as optval_n:
await _setsockopt(self.task.sysif, self.near, level, optname, optval_n, optval.size())
async def getsockname(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) -> Pointer[Sockbuf[T_sockaddr]]:
self._validate()
with addr.borrow(self.task) as addr_n:
with addr.value.buf.borrow(self.task) as addrbuf_n:
await _getsockname(self.task.sysif, self.near, addrbuf_n, addr_n)
return addr
async def getpeername(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) -> Pointer[Sockbuf[T_sockaddr]]:
self._validate()
with addr.borrow(self.task) as addr_n:
with addr.value.buf.borrow(self.task) as addrbuf_n:
await _getpeername(self.task.sysif, self.near, addrbuf_n, addr_n)
return addr
@t.overload
async def accept(self: T_fd, flags: SOCK=SOCK.NONE) -> T_fd: ...
@t.overload
async def accept(self: T_fd, flags: SOCK, addr: WrittenPointer[Sockbuf[T_sockaddr]]
) -> t.Tuple[T_fd, WrittenPointer[Sockbuf[T_sockaddr]]]: ...
async def accept(self: T_fd, flags: SOCK=SOCK.NONE,
addr: t.Optional[WrittenPointer[Sockbuf[T_sockaddr]]]=None
) -> t.Union[T_fd, t.Tuple[T_fd, WrittenPointer[Sockbuf[T_sockaddr]]]]:
self._validate()
flags |= SOCK.CLOEXEC
if addr is None:
fd = await _accept(self.task.sysif, self.near, None, None, flags)
return self.task.make_fd_handle(fd)
else:
with addr.borrow(self.task):
with addr.value.buf.borrow(self.task):
fd = await _accept(self.task.sysif, self.near,
addr.value.buf.near, addr.near, flags)
return self.task.make_fd_handle(fd), addr
async def shutdown(self, how: SHUT) -> None:
self._validate()
await _shutdown(self.task.sysif, self.near, how)
async def sendmsg(self, msg: WrittenPointer[SendMsghdr], flags: SendmsgFlags=SendmsgFlags.NONE
) -> t.Tuple[IovecList, IovecList]:
"""send a message on a socket
man: sendmsg(2)
"""
with contextlib.ExitStack() as stack:
stack.enter_context(msg.borrow(self.task))
if msg.value.name:
stack.enter_context(msg.value.name.borrow(self.task))
if msg.value.control:
stack.enter_context(msg.value.control.borrow(self.task))
msg.value.control.value.borrow_with(stack, self.task)
stack.enter_context(msg.value.iov.borrow(self.task))
for iovec_elem in msg.value.iov.value:
stack.enter_context(iovec_elem.borrow(self.task))
ret = await _sendmsg(self.task.sysif, self.near, msg.near, flags)
return msg.value.iov.value.split(ret)
async def recvmsg(self, msg: WrittenPointer[RecvMsghdr], flags: RecvmsgFlags=RecvmsgFlags.NONE,
) -> t.Tuple[IovecList, IovecList, Pointer[RecvMsghdrOut]]:
"""receive a message from a socket
man: recvmsg(2)
"""
flags |= RecvmsgFlags.CMSG_CLOEXEC
with contextlib.ExitStack() as stack:
stack.enter_context(msg.borrow(self.task))
if msg.value.name:
stack.enter_context(msg.value.name.borrow(self.task))
if msg.value.control:
stack.enter_context(msg.value.control.borrow(self.task))
stack.enter_context(msg.value.iov.borrow(self.task))
for iovec_elem in msg.value.iov.value:
stack.enter_context(iovec_elem.borrow(self.task))
ret = await _recvmsg(self.task.sysif, self.near, msg.near, flags)
valid, invalid = msg.value.iov.value.split(ret)
return valid, invalid, msg.value.to_out(msg)
async def recv(self, buf: Pointer[T], flags: MSG) -> t.Tuple[ReadablePointer[T], Pointer]:
"""receive a message from a socket
man: recv(2)
"""
self._validate()
with buf.borrow(self.task) as buf_n:
ret = await _recv(self.task.sysif, self.near, buf_n, buf.size(), flags)
return buf.readable_split(ret)
async def send(self, buf: Pointer[T], flags: MSG) -> t.Tuple[Pointer[T], Pointer]:
"""send a message on a socket
man: send(2)
"""
self._validate()
with buf.borrow(self.task) as buf_n:
ret = await _send(self.task.sysif, self.near, buf_n, buf.size(), flags)
return buf.split(ret)
class SocketTask(FileDescriptorTask[T_fd]):
async def socket(self, domain: AF, type: SOCK, protocol: int=0) -> T_fd:
"""create an endpoint for communication
manpage: socket(2)
"""
sockfd = await _socket(self.sysif, domain, type|SOCK.CLOEXEC, protocol)
return self.make_fd_handle(sockfd)
async def socketpair(self, domain: AF, type: SOCK, protocol: int,
sv: Pointer[Socketpair]) -> LinearPointer[Socketpair]:
with sv.borrow(self) as sv_n:
await _socketpair(self.sysif, domain, type|SOCK.CLOEXEC, protocol, sv_n)
return sv._linearize()
#### Raw syscalls ####
from rsyscall.near.sysif import SyscallInterface
from rsyscall.sys.syscall import SYS
async def _socket(sysif: SyscallInterface,
domain: AF, type: SOCK, protocol: int) -> near.FileDescriptor:
return near.FileDescriptor(await sysif.syscall(SYS.socket, domain, type, protocol))
async def _socketpair(sysif: SyscallInterface,
domain: AF, type: SOCK, protocol: int, sv: near.Address) -> None:
await sysif.syscall(SYS.socketpair, domain, type, protocol, sv)
async def _bind(sysif: SyscallInterface, sockfd: near.FileDescriptor,
addr: near.Address, addrlen: int) -> None:
await sysif.syscall(SYS.bind, sockfd, addr, addrlen)
async def _connect(sysif: SyscallInterface, sockfd: near.FileDescriptor,
addr: near.Address, addrlen: int) -> None:
await sysif.syscall(SYS.connect, sockfd, addr, addrlen)
async def _listen(sysif: SyscallInterface, sockfd: near.FileDescriptor,
backlog: int) -> None:
await sysif.syscall(SYS.listen, sockfd, backlog)
async def _accept(sysif: SyscallInterface, sockfd: near.FileDescriptor,
addr: t.Optional[near.Address], addrlen: t.Optional[near.Address],
flags: SOCK) -> near.FileDescriptor:
if addr is None:
addr = 0 # type: ignore
if addrlen is None:
addrlen = 0 # type: ignore
return near.FileDescriptor(await sysif.syscall(SYS.accept4, sockfd, addr, addrlen, flags))
async def _shutdown(sysif: SyscallInterface, sockfd: near.FileDescriptor, how: SHUT) -> None:
await sysif.syscall(SYS.shutdown, sockfd, how)
async def _getsockname(sysif: SyscallInterface, sockfd: near.FileDescriptor,
addr: near.Address, addrlen: near.Address) -> None:
await sysif.syscall(SYS.getsockname, sockfd, addr, addrlen)
async def _getpeername(sysif: SyscallInterface, sockfd: near.FileDescriptor,
addr: near.Address, addrlen: near.Address) -> None:
await sysif.syscall(SYS.getpeername, sockfd, addr, addrlen)
async def _getsockopt(sysif: SyscallInterface, sockfd: near.FileDescriptor,
level: int, optname: int, optval: near.Address, optlen: near.Address) -> None:
await sysif.syscall(SYS.getsockopt, sockfd, level, optname, optval, optlen)
async def _setsockopt(sysif: SyscallInterface, sockfd: near.FileDescriptor,
level: int, optname: int, optval: near.Address, optlen: int) -> None:
await sysif.syscall(SYS.setsockopt, sockfd, level, optname, optval, optlen)
async def _recv(sysif: SyscallInterface, fd: near.FileDescriptor,
buf: near.Address, count: int, flags: int) -> int:
return (await sysif.syscall(SYS.recvfrom, fd, buf, count, flags))
async def _send(sysif: SyscallInterface, fd: near.FileDescriptor,
buf: near.Address, count: int, flags: int) -> int:
return (await sysif.syscall(SYS.sendto, fd, buf, count, flags))
async def _recvmsg(sysif: SyscallInterface, fd: near.FileDescriptor,
msg: near.Address, flags: int) -> int:
return (await sysif.syscall(SYS.recvmsg, fd, msg, flags))
async def _sendmsg(sysif: SyscallInterface, fd: near.FileDescriptor,
msg: near.Address, flags: int) -> int:
return (await sysif.syscall(SYS.sendmsg, fd, msg, flags))
#### Tests ####
from unittest import TestCase
class TestSocket(TestCase):
pass
Classes
class AF (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class AF(enum.IntEnum): UNIX = lib.AF_UNIX NETLINK = lib.AF_NETLINK INET = lib.AF_INET INET6 = lib.AF_INET6
Ancestors
- enum.IntEnum
- builtins.int
- enum.Enum
Class variables
var UNIX
var NETLINK
var INET
var INET6
class SHUT (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class SHUT(enum.IntEnum): RD = lib.SHUT_RD WR = lib.SHUT_WR RDWR = lib.SHUT_RDWR
Ancestors
- enum.IntEnum
- builtins.int
- enum.Enum
Class variables
var RD
var WR
var RDWR
class Sockaddr (family: AF, data: bytes)
-
struct sockaddr. This is not really useful to allocate on its own; you want the derived classes.
Expand source code Browse git
class Sockaddr(Struct): """struct sockaddr. This is not really useful to allocate on its own; you want the derived classes. """ def __init__(self, family: AF, data: bytes) -> None: self.family = family self.data = data @classmethod def check_family(cls, family: AF) -> None: if cls.family != family: raise Exception("sa_family should be", cls.family, "is instead", family) def to_bytes(self) -> bytes: struct = ffi.new('struct sockaddr*', (self.family, self.data)) return bytes(ffi.buffer(struct)) T = t.TypeVar('T', bound='Sockaddr') @classmethod def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct sockaddr*', ffi.from_buffer(data)) return cls(struct.sa_family, bytes(ffi.buffer(struct.sa_data))) @classmethod def sizeof(cls) -> int: return ffi.sizeof('struct sockaddr') def parse(self) -> Sockaddr: "Using the family field, return the correct Sockaddr type that this actually contains." cls = family_to_class[self.family] return cls.from_bytes(self.to_bytes())
Ancestors
Subclasses
Class variables
var T
Static methods
def check_family(family: AF) ‑> NoneType
-
Expand source code Browse git
@classmethod def check_family(cls, family: AF) -> None: if cls.family != family: raise Exception("sa_family should be", cls.family, "is instead", family)
Methods
def parse(self) ‑> Sockaddr
-
Using the family field, return the correct Sockaddr type that this actually contains.
Expand source code Browse git
def parse(self) -> Sockaddr: "Using the family field, return the correct Sockaddr type that this actually contains." cls = family_to_class[self.family] return cls.from_bytes(self.to_bytes())
Inherited members
class SockaddrStorage (family: AF, data: bytes)
-
struct sockaddr_storage. Useful when dealing with sockets with unknown address families
Expand source code Browse git
@dataclass class SockaddrStorage(Sockaddr): "struct sockaddr_storage. Useful when dealing with sockets with unknown address families" family: AF data: bytes def to_bytes(self) -> bytes: # We can't just create a struct sockaddr_storage and turn the whole thing to bytes, # because that will pad the actually valid data with a bunch of trailing null bytes. # And we can't do that because the length of the valid data is semantically # meaningful for some socket addresses, such as sockaddr_un. return bytes(ffi.buffer(ffi.new('sa_family_t*', self.family))) + self.data T = t.TypeVar('T', bound='SockaddrStorage') @classmethod def from_bytes(cls: t.Type[T], data: bytes) -> T: # As with to_bytes, we can't just cast the bytes to a struct sockaddr_storage and read its data field, # because that would pad the data with a bunch of null bytes, # and would not preserve the length of the valid data family = ffi.cast('sa_family_t*', ffi.from_buffer(data)) rest = data[ffi.sizeof('sa_family_t'):] return cls( family=AF(family[0]), data=rest ) @classmethod def sizeof(cls) -> int: return ffi.sizeof('struct sockaddr_storage')
Ancestors
Class variables
var family : AF
var data : bytes
var T
Inherited members
class SOCK (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class SOCK(enum.IntFlag): NONE = 0 # socket kinds DGRAM = lib.SOCK_DGRAM STREAM = lib.SOCK_STREAM SEQPACKET = lib.SOCK_SEQPACKET RAW = lib.SOCK_RAW # flags that can be or'd in CLOEXEC = lib.SOCK_CLOEXEC NONBLOCK = lib.SOCK_NONBLOCK
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var NONE
var DGRAM
var STREAM
var SEQPACKET
var RAW
var CLOEXEC
var NONBLOCK
class SOL (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
Stands for Sock Opt Level
This is what should be passed as the "level" argument to getsockopt/setsockopt.
Expand source code Browse git
class SOL(enum.IntEnum): """Stands for Sock Opt Level This is what should be passed as the "level" argument to getsockopt/setsockopt. """ SOCKET = lib.SOL_SOCKET IP = lib.SOL_IP
Ancestors
- enum.IntEnum
- builtins.int
- enum.Enum
Class variables
var SOCKET
var IP
class SO (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class SO(enum.IntEnum): ACCEPTCONN = lib.SO_ACCEPTCONN ATTACH_FILTER = lib.SO_ATTACH_FILTER ATTACH_BPF = lib.SO_ATTACH_BPF ATTACH_REUSEPORT_CBPF = lib.SO_ATTACH_REUSEPORT_CBPF ATTACH_REUSEPORT_EBPF = lib.SO_ATTACH_REUSEPORT_EBPF BINDTODEVICE = lib.SO_BINDTODEVICE BROADCAST = lib.SO_BROADCAST BSDCOMPAT = lib.SO_BSDCOMPAT DEBUG = lib.SO_DEBUG DETACH_FILTER = lib.SO_DETACH_FILTER DETACH_BPF = lib.SO_DETACH_BPF DOMAIN = lib.SO_DOMAIN ERROR = lib.SO_ERROR DONTROUTE = lib.SO_DONTROUTE INCOMING_CPU = lib.SO_INCOMING_CPU KEEPALIVE = lib.SO_KEEPALIVE LINGER = lib.SO_LINGER LOCK_FILTER = lib.SO_LOCK_FILTER MARK = lib.SO_MARK OOBINLINE = lib.SO_OOBINLINE PASSCRED = lib.SO_PASSCRED PEEK_OFF = lib.SO_PEEK_OFF PEERCRED = lib.SO_PEERCRED PRIORITY = lib.SO_PRIORITY PROTOCOL = lib.SO_PROTOCOL RCVBUF = lib.SO_RCVBUF RCVBUFFORCE = lib.SO_RCVBUFFORCE RCVLOWAT = lib.SO_RCVLOWAT SNDLOWAT = lib.SO_SNDLOWAT RCVTIMEO = lib.SO_RCVTIMEO SNDTIMEO = lib.SO_SNDTIMEO REUSEADDR = lib.SO_REUSEADDR REUSEPORT = lib.SO_REUSEPORT RXQ_OVFL = lib.SO_RXQ_OVFL SNDBUF = lib.SO_SNDBUF SNDBUFFORCE = lib.SO_SNDBUFFORCE TIMESTAMP = lib.SO_TIMESTAMP TYPE = lib.SO_TYPE BUSY_POLL = lib.SO_BUSY_POLL
Ancestors
- enum.IntEnum
- builtins.int
- enum.Enum
Class variables
var ACCEPTCONN
var ATTACH_FILTER
var ATTACH_BPF
var ATTACH_REUSEPORT_CBPF
var ATTACH_REUSEPORT_EBPF
var BINDTODEVICE
var BROADCAST
var BSDCOMPAT
var DEBUG
var DETACH_FILTER
var DETACH_BPF
var DOMAIN
var ERROR
var DONTROUTE
var INCOMING_CPU
var KEEPALIVE
var LINGER
var LOCK_FILTER
var MARK
var OOBINLINE
var PASSCRED
var PEEK_OFF
var PEERCRED
var PRIORITY
var PROTOCOL
var RCVBUF
var RCVBUFFORCE
var RCVLOWAT
var SNDLOWAT
var RCVTIMEO
var SNDTIMEO
var REUSEADDR
var REUSEPORT
var RXQ_OVFL
var SNDBUF
var SNDBUFFORCE
var TIMESTAMP
var TYPE
var BUSY_POLL
class MSG (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class MSG(enum.IntFlag): NONE = 0 # send flags CONFIRM = lib.MSG_CONFIRM DONTROUTE = lib.MSG_DONTROUTE EOR = lib.MSG_EOR MORE = lib.MSG_MORE NOSIGNAL = lib.MSG_NOSIGNAL # recv flags CMSG_CLOEXEC = lib.MSG_CMSG_CLOEXEC ERRQUEUE = lib.MSG_ERRQUEUE PEEK = lib.MSG_PEEK TRUNC = lib.MSG_TRUNC WAITALL = lib.MSG_WAITALL # both DONTWAIT = lib.MSG_DONTWAIT OOB = lib.MSG_OOB
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var NONE
var CONFIRM
var DONTROUTE
var EOR
var MORE
var NOSIGNAL
var CMSG_CLOEXEC
var ERRQUEUE
var PEEK
var TRUNC
var WAITALL
var DONTWAIT
var OOB
class Socketpair (first: FileDescriptor, second: FileDescriptor)
-
Socketpair(first: 'FileDescriptor', second: 'FileDescriptor')
Expand source code Browse git
@dataclass class Socketpair(FixedSize): first: FileDescriptor second: FileDescriptor @classmethod def sizeof(cls) -> int: return ffi.sizeof('struct fdpair') @classmethod def get_serializer(cls: t.Type[T_socketpair], task: Task) -> Serializer[T_socketpair]: return SocketpairSerializer(cls, task)
Ancestors
Class variables
var first : object
var second : object
Inherited members
class Sockbuf (buf: Pointer[T], buf_rest: t.Optional[Pointer[T]] = None)
-
Sockbuf(buf: 'Pointer[T]', buf_rest: 't.Optional[Pointer[T]]' = None)
Expand source code Browse git
@dataclass class Sockbuf(t.Generic[T], HasSerializer): buf: Pointer[T] buf_rest: t.Optional[Pointer[T]] = None def get_self_serializer(self, task: Task) -> SockbufSerializer[T]: return SockbufSerializer(self.buf)
Ancestors
- typing.Generic
- HasSerializer
Class variables
var buf : Pointer[~T]
var buf_rest : Optional[Pointer[~T]]
Inherited members
class CmsgSCMRights (*args, **kwargs)
-
Something which, if we know its class, can be serialized and deserialized
Expand source code Browse git
class CmsgSCMRights(Cmsg, t.List[FileDescriptor]): def to_data(self) -> bytes: return array.array('i', (int(fd) for fd in self)).tobytes() def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) -> None: for fd in self: stack.enter_context(fd.borrow(task)) T = t.TypeVar('T', bound='CmsgSCMRights') @classmethod def from_data(cls: t.Type[T], task: Task, data: bytes) -> T: fds = [near.FileDescriptor(fd) for fd, in struct.Struct('i').iter_unpack(data)] return cls([task.make_fd_handle(fd) for fd in fds]) @classmethod def level(cls) -> SOL: return SOL.SOCKET @classmethod def type(cls) -> int: return SCM.RIGHTS
Ancestors
- rsyscall.sys.socket.Cmsg
- FixedSerializer
- HasSerializer
- builtins.list
- typing.Generic
Class variables
var T
Static methods
def from_data(task: Task, data: bytes) ‑> T
-
Expand source code Browse git
@classmethod def from_data(cls: t.Type[T], task: Task, data: bytes) -> T: fds = [near.FileDescriptor(fd) for fd, in struct.Struct('i').iter_unpack(data)] return cls([task.make_fd_handle(fd) for fd in fds])
def level() ‑> SOL
-
Expand source code Browse git
@classmethod def level(cls) -> SOL: return SOL.SOCKET
def type() ‑> int
-
Expand source code Browse git
@classmethod def type(cls) -> int: return SCM.RIGHTS
Methods
def to_data(self) ‑> bytes
-
Expand source code Browse git
def to_data(self) -> bytes: return array.array('i', (int(fd) for fd in self)).tobytes()
def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) ‑> NoneType
-
Expand source code Browse git
def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) -> None: for fd in self: stack.enter_context(fd.borrow(task))
Inherited members
class CmsgList (*args, **kwargs)
-
Built-in mutable sequence.
If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.
Expand source code Browse git
class CmsgList(t.List[Cmsg], FixedSerializer): @classmethod def get_serializer(cls: t.Type[T_cmsglist], task: Task) -> Serializer[T_cmsglist]: return CmsgListSerializer(cls, task) def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) -> None: for cmsg in self: cmsg.borrow_with(stack, task)
Ancestors
- builtins.list
- typing.Generic
- FixedSerializer
- HasSerializer
Methods
def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) ‑> NoneType
-
Expand source code Browse git
def borrow_with(self, stack: contextlib.ExitStack, task: FileDescriptorTask) -> None: for cmsg in self: cmsg.borrow_with(stack, task)
Inherited members
class SendMsghdr (name: t.Optional[WrittenPointer[Sockaddr]], iov: WrittenPointer[IovecList], control: t.Optional[WrittenPointer[CmsgList]])
-
SendMsghdr(name: 't.Optional[WrittenPointer[Sockaddr]]', iov: 'WrittenPointer[IovecList]', control: 't.Optional[WrittenPointer[CmsgList]]')
Expand source code Browse git
@dataclass class SendMsghdr(Serializable): name: t.Optional[WrittenPointer[Sockaddr]] iov: WrittenPointer[IovecList] control: t.Optional[WrittenPointer[CmsgList]] def to_bytes(self) -> bytes: return bytes(ffi.buffer(ffi.new('struct msghdr*', { "msg_name": ffi.cast('void*', int(self.name.near)) if self.name else ffi.NULL, "msg_namelen": self.name.size() if self.name else 0, "msg_iov": ffi.cast('void*', int(self.iov.near)), "msg_iovlen": len(self.iov.value), "msg_control": ffi.cast('void*', int(self.control.near)) if self.control else ffi.NULL, "msg_controllen": self.control.size() if self.control else 0, "msg_flags": 0, }))) T = t.TypeVar('T', bound='SendMsghdr') @classmethod def from_bytes(cls: t.Type[T], data: bytes) -> T: raise Exception("can't get pointer handles from raw bytes")
Ancestors
Class variables
var name : Optional[WrittenPointer[Sockaddr]]
var iov : WrittenPointer[IovecList]
var control : Optional[WrittenPointer[CmsgList]]
var T
Inherited members
class RecvMsghdr (name: t.Optional[Pointer[Sockaddr]], iov: WrittenPointer[IovecList], control: t.Optional[Pointer[CmsgList]])
-
RecvMsghdr(name: 't.Optional[Pointer[Sockaddr]]', iov: 'WrittenPointer[IovecList]', control: 't.Optional[Pointer[CmsgList]]')
Expand source code Browse git
@dataclass class RecvMsghdr(Serializable): name: t.Optional[Pointer[Sockaddr]] iov: WrittenPointer[IovecList] control: t.Optional[Pointer[CmsgList]] def to_bytes(self) -> bytes: return bytes(ffi.buffer(ffi.new('struct msghdr*', { "msg_name": ffi.cast('void*', int(self.name.near)) if self.name else ffi.NULL, "msg_namelen": self.name.size() if self.name else 0, "msg_iov": ffi.cast('void*', int(self.iov.near)), "msg_iovlen": len(self.iov.value), "msg_control": ffi.cast('void*', int(self.control.near)) if self.control else ffi.NULL, "msg_controllen": self.control.size() if self.control else 0, "msg_flags": 0, }))) T = t.TypeVar('T', bound='RecvMsghdr') @classmethod def from_bytes(cls: t.Type[T], data: bytes) -> T: raise Exception("can't get pointer handles from raw bytes") def to_out(self, ptr: Pointer[RecvMsghdr]) -> Pointer[RecvMsghdrOut]: # what a mouthful serializer = RecvMsghdrOutSerializer(self.name, self.control) return ptr._reinterpret(serializer, RecvMsghdrOut)
Ancestors
Class variables
var name : Optional[Pointer[Sockaddr]]
var iov : WrittenPointer[IovecList]
var control : Optional[Pointer[CmsgList]]
var T
Methods
def to_out(self, ptr: Pointer[RecvMsghdr]) ‑> Pointer[RecvMsghdrOut]
-
Expand source code Browse git
def to_out(self, ptr: Pointer[RecvMsghdr]) -> Pointer[RecvMsghdrOut]: # what a mouthful serializer = RecvMsghdrOutSerializer(self.name, self.control) return ptr._reinterpret(serializer, RecvMsghdrOut)
Inherited members
class RecvMsghdrOut (name: t.Optional[ReadablePointer[Sockaddr]], control: t.Optional[LinearPointer[CmsgList]], flags: MsghdrFlags, name_rest: t.Optional[Pointer[Sockaddr]], control_rest: t.Optional[Pointer[CmsgList]])
-
RecvMsghdrOut(name: 't.Optional[ReadablePointer[Sockaddr]]', control: 't.Optional[LinearPointer[CmsgList]]', flags: 'MsghdrFlags', name_rest: 't.Optional[Pointer[Sockaddr]]', control_rest: 't.Optional[Pointer[CmsgList]]')
Expand source code Browse git
@dataclass class RecvMsghdrOut: name: t.Optional[ReadablePointer[Sockaddr]] control: t.Optional[LinearPointer[CmsgList]] flags: MsghdrFlags # the _rest fields are the invalid, unused parts of the buffers; # almost everyone can ignore these. name_rest: t.Optional[Pointer[Sockaddr]] control_rest: t.Optional[Pointer[CmsgList]]
Class variables
var name : Optional[ReadablePointer[Sockaddr]]
var control : Optional[LinearPointer[CmsgList]]
var flags : MsghdrFlags
var name_rest : Optional[Pointer[Sockaddr]]
var control_rest : Optional[Pointer[CmsgList]]
class SendmsgFlags (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class SendmsgFlags(enum.IntFlag): NONE = 0
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var NONE
class RecvmsgFlags (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class RecvmsgFlags(enum.IntFlag): NONE = 0 CMSG_CLOEXEC = lib.MSG_CMSG_CLOEXEC
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var NONE
var CMSG_CLOEXEC
class MsghdrFlags (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code Browse git
class MsghdrFlags(enum.IntFlag): NONE = 0 CTRUNC = lib.MSG_CTRUNC CMSG_CLOEXEC = lib.MSG_CMSG_CLOEXEC
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var NONE
var CTRUNC
var CMSG_CLOEXEC
class SocketTask (sysif: SyscallInterface, near_process: Process, fd_table: FDTable, address_space: AddressSpace, pidns: PidNamespace)
-
A wrapper around
SyscallInterface
which tracks the namespaces of the underlying processNote that this is a base class for the more fully featured
Task
.We store namespace objects to represent the namespaces that we believe that underlying processes is in. Since we have complete control over the process, we can make sure this belief is accurate, by updating our stored namespaces when the process changes namespace. That isn't done here; it's done in handle.Task.
Currently, we store only one
PidNamespace
. But each process actually has two pid namespaces:- the process's own pid namespace, which determines the pids returned from getpid, clone, and other syscalls.
- the pid namespace that new children will be in.
The two pid namespaces only differ if we call unshare(CLONE.NEWPID). Currently we don't do that because unshare(CLONE.NEWPID) makes monitoring children more complex, since they can be deleted without leaving a zombie at any time if the pid namespace shuts down. But if we did call unshare(CLONE.NEWPID), we'd need to handle this right.
In the analogy to near and far pointers, this is like a segment register, if a segment register was write-only. Then we'd need to maintain the knowledge of what the segment register was set to, outside the segment register itself. That's what we do here.
There actually were systems where segment registers were, if not quite write-only, at least expensive to set and expensive to read. For example, x86_64 - the FS and GS segment registers can only be set via syscall. If you wanted to use segmentation on such systems, you'd probably have a structure much like this one.
Expand source code Browse git
class SocketTask(FileDescriptorTask[T_fd]): async def socket(self, domain: AF, type: SOCK, protocol: int=0) -> T_fd: """create an endpoint for communication manpage: socket(2) """ sockfd = await _socket(self.sysif, domain, type|SOCK.CLOEXEC, protocol) return self.make_fd_handle(sockfd) async def socketpair(self, domain: AF, type: SOCK, protocol: int, sv: Pointer[Socketpair]) -> LinearPointer[Socketpair]: with sv.borrow(self) as sv_n: await _socketpair(self.sysif, domain, type|SOCK.CLOEXEC, protocol, sv_n) return sv._linearize()
Ancestors
- FileDescriptorTask
- Task
- typing.Generic
Subclasses
Class variables
var sysif : SyscallInterface
var near_process : Process
var fd_table : FDTable
var address_space : AddressSpace
var pidns : PidNamespace
Methods
async def socket(self, domain: AF, type: SOCK, protocol: int = 0) ‑> ~T_fd
-
create an endpoint for communication
manpage: socket(2)
Expand source code Browse git
async def socket(self, domain: AF, type: SOCK, protocol: int=0) -> T_fd: """create an endpoint for communication manpage: socket(2) """ sockfd = await _socket(self.sysif, domain, type|SOCK.CLOEXEC, protocol) return self.make_fd_handle(sockfd)
async def socketpair(self, domain: AF, type: SOCK, protocol: int, sv: Pointer[Socketpair]) ‑> LinearPointer[Socketpair]
-
Expand source code Browse git
async def socketpair(self, domain: AF, type: SOCK, protocol: int, sv: Pointer[Socketpair]) -> LinearPointer[Socketpair]: with sv.borrow(self) as sv_n: await _socketpair(self.sysif, domain, type|SOCK.CLOEXEC, protocol, sv_n) return sv._linearize()
Inherited members
class SocketFileDescriptor (task: FileDescriptorTask, near: FileDescriptor, valid: bool)
-
A file descriptor accessed through some
Task
This is an rsyscall-internal base class, which other
FileDescriptor
objects inherit from for core lifecycle methods. SeeFileDescriptor
for more information.Expand source code Browse git
class SocketFileDescriptor(BaseFileDescriptor): async def bind(self, addr: WrittenPointer[Sockaddr]) -> None: """bind a name to a socket man: bind(2) """ self._validate() with addr.borrow(self.task): try: await _bind(self.task.sysif, self.near, addr.near, addr.size()) except PermissionError as exn: exn.filename = addr.value raise except FileNotFoundError as exn: exn.filename = addr.value raise async def connect(self, addr: WrittenPointer[Sockaddr]) -> None: self._validate() with addr.borrow(self.task): try: await _connect(self.task.sysif, self.near, addr.near, addr.size()) except OSError as exn: exn.filename = self if hasattr(addr, 'value'): exn.filename2 = addr.value raise async def listen(self, backlog: int) -> None: self._validate() await _listen(self.task.sysif, self.near, backlog) async def getsockopt(self, level: int, optname: int, optval: WrittenPointer[Sockbuf[T]]) -> Pointer[Sockbuf[T]]: self._validate() with optval.borrow(self.task): with optval.value.buf.borrow(self.task): await _getsockopt(self.task.sysif, self.near, level, optname, optval.value.buf.near, optval.near) return optval async def setsockopt(self, level: int, optname: int, optval: Pointer) -> None: self._validate() with optval.borrow(self.task) as optval_n: await _setsockopt(self.task.sysif, self.near, level, optname, optval_n, optval.size()) async def getsockname(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) -> Pointer[Sockbuf[T_sockaddr]]: self._validate() with addr.borrow(self.task) as addr_n: with addr.value.buf.borrow(self.task) as addrbuf_n: await _getsockname(self.task.sysif, self.near, addrbuf_n, addr_n) return addr async def getpeername(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) -> Pointer[Sockbuf[T_sockaddr]]: self._validate() with addr.borrow(self.task) as addr_n: with addr.value.buf.borrow(self.task) as addrbuf_n: await _getpeername(self.task.sysif, self.near, addrbuf_n, addr_n) return addr @t.overload async def accept(self: T_fd, flags: SOCK=SOCK.NONE) -> T_fd: ... @t.overload async def accept(self: T_fd, flags: SOCK, addr: WrittenPointer[Sockbuf[T_sockaddr]] ) -> t.Tuple[T_fd, WrittenPointer[Sockbuf[T_sockaddr]]]: ... async def accept(self: T_fd, flags: SOCK=SOCK.NONE, addr: t.Optional[WrittenPointer[Sockbuf[T_sockaddr]]]=None ) -> t.Union[T_fd, t.Tuple[T_fd, WrittenPointer[Sockbuf[T_sockaddr]]]]: self._validate() flags |= SOCK.CLOEXEC if addr is None: fd = await _accept(self.task.sysif, self.near, None, None, flags) return self.task.make_fd_handle(fd) else: with addr.borrow(self.task): with addr.value.buf.borrow(self.task): fd = await _accept(self.task.sysif, self.near, addr.value.buf.near, addr.near, flags) return self.task.make_fd_handle(fd), addr async def shutdown(self, how: SHUT) -> None: self._validate() await _shutdown(self.task.sysif, self.near, how) async def sendmsg(self, msg: WrittenPointer[SendMsghdr], flags: SendmsgFlags=SendmsgFlags.NONE ) -> t.Tuple[IovecList, IovecList]: """send a message on a socket man: sendmsg(2) """ with contextlib.ExitStack() as stack: stack.enter_context(msg.borrow(self.task)) if msg.value.name: stack.enter_context(msg.value.name.borrow(self.task)) if msg.value.control: stack.enter_context(msg.value.control.borrow(self.task)) msg.value.control.value.borrow_with(stack, self.task) stack.enter_context(msg.value.iov.borrow(self.task)) for iovec_elem in msg.value.iov.value: stack.enter_context(iovec_elem.borrow(self.task)) ret = await _sendmsg(self.task.sysif, self.near, msg.near, flags) return msg.value.iov.value.split(ret) async def recvmsg(self, msg: WrittenPointer[RecvMsghdr], flags: RecvmsgFlags=RecvmsgFlags.NONE, ) -> t.Tuple[IovecList, IovecList, Pointer[RecvMsghdrOut]]: """receive a message from a socket man: recvmsg(2) """ flags |= RecvmsgFlags.CMSG_CLOEXEC with contextlib.ExitStack() as stack: stack.enter_context(msg.borrow(self.task)) if msg.value.name: stack.enter_context(msg.value.name.borrow(self.task)) if msg.value.control: stack.enter_context(msg.value.control.borrow(self.task)) stack.enter_context(msg.value.iov.borrow(self.task)) for iovec_elem in msg.value.iov.value: stack.enter_context(iovec_elem.borrow(self.task)) ret = await _recvmsg(self.task.sysif, self.near, msg.near, flags) valid, invalid = msg.value.iov.value.split(ret) return valid, invalid, msg.value.to_out(msg) async def recv(self, buf: Pointer[T], flags: MSG) -> t.Tuple[ReadablePointer[T], Pointer]: """receive a message from a socket man: recv(2) """ self._validate() with buf.borrow(self.task) as buf_n: ret = await _recv(self.task.sysif, self.near, buf_n, buf.size(), flags) return buf.readable_split(ret) async def send(self, buf: Pointer[T], flags: MSG) -> t.Tuple[Pointer[T], Pointer]: """send a message on a socket man: send(2) """ self._validate() with buf.borrow(self.task) as buf_n: ret = await _send(self.task.sysif, self.near, buf_n, buf.size(), flags) return buf.split(ret)
Ancestors
Subclasses
Methods
async def bind(self, addr: WrittenPointer[Sockaddr]) ‑> NoneType
-
bind a name to a socket
man: bind(2)
Expand source code Browse git
async def bind(self, addr: WrittenPointer[Sockaddr]) -> None: """bind a name to a socket man: bind(2) """ self._validate() with addr.borrow(self.task): try: await _bind(self.task.sysif, self.near, addr.near, addr.size()) except PermissionError as exn: exn.filename = addr.value raise except FileNotFoundError as exn: exn.filename = addr.value raise
async def connect(self, addr: WrittenPointer[Sockaddr]) ‑> NoneType
-
Expand source code Browse git
async def connect(self, addr: WrittenPointer[Sockaddr]) -> None: self._validate() with addr.borrow(self.task): try: await _connect(self.task.sysif, self.near, addr.near, addr.size()) except OSError as exn: exn.filename = self if hasattr(addr, 'value'): exn.filename2 = addr.value raise
async def listen(self, backlog: int) ‑> NoneType
-
Expand source code Browse git
async def listen(self, backlog: int) -> None: self._validate() await _listen(self.task.sysif, self.near, backlog)
async def getsockopt(self, level: int, optname: int, optval: WrittenPointer[Sockbuf[T]]) ‑> Pointer[Sockbuf[~T]]
-
Expand source code Browse git
async def getsockopt(self, level: int, optname: int, optval: WrittenPointer[Sockbuf[T]]) -> Pointer[Sockbuf[T]]: self._validate() with optval.borrow(self.task): with optval.value.buf.borrow(self.task): await _getsockopt(self.task.sysif, self.near, level, optname, optval.value.buf.near, optval.near) return optval
async def setsockopt(self, level: int, optname: int, optval: Pointer) ‑> NoneType
-
Expand source code Browse git
async def setsockopt(self, level: int, optname: int, optval: Pointer) -> None: self._validate() with optval.borrow(self.task) as optval_n: await _setsockopt(self.task.sysif, self.near, level, optname, optval_n, optval.size())
async def getsockname(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) ‑> Pointer[Sockbuf[~T_sockaddr]]
-
Expand source code Browse git
async def getsockname(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) -> Pointer[Sockbuf[T_sockaddr]]: self._validate() with addr.borrow(self.task) as addr_n: with addr.value.buf.borrow(self.task) as addrbuf_n: await _getsockname(self.task.sysif, self.near, addrbuf_n, addr_n) return addr
async def getpeername(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) ‑> Pointer[Sockbuf[~T_sockaddr]]
-
Expand source code Browse git
async def getpeername(self, addr: WrittenPointer[Sockbuf[T_sockaddr]]) -> Pointer[Sockbuf[T_sockaddr]]: self._validate() with addr.borrow(self.task) as addr_n: with addr.value.buf.borrow(self.task) as addrbuf_n: await _getpeername(self.task.sysif, self.near, addrbuf_n, addr_n) return addr
async def accept(self: T_fd, flags: SOCK = SOCK.NONE, addr: t.Optional[WrittenPointer[Sockbuf[T_sockaddr]]] = None) ‑> Union[~T_fd, Tuple[~T_fd, WrittenPointer[Sockbuf[~T_sockaddr]]]]
-
Expand source code Browse git
async def accept(self: T_fd, flags: SOCK=SOCK.NONE, addr: t.Optional[WrittenPointer[Sockbuf[T_sockaddr]]]=None ) -> t.Union[T_fd, t.Tuple[T_fd, WrittenPointer[Sockbuf[T_sockaddr]]]]: self._validate() flags |= SOCK.CLOEXEC if addr is None: fd = await _accept(self.task.sysif, self.near, None, None, flags) return self.task.make_fd_handle(fd) else: with addr.borrow(self.task): with addr.value.buf.borrow(self.task): fd = await _accept(self.task.sysif, self.near, addr.value.buf.near, addr.near, flags) return self.task.make_fd_handle(fd), addr
async def shutdown(self, how: SHUT) ‑> NoneType
-
Expand source code Browse git
async def shutdown(self, how: SHUT) -> None: self._validate() await _shutdown(self.task.sysif, self.near, how)
async def sendmsg(self, msg: WrittenPointer[SendMsghdr], flags: SendmsgFlags = SendmsgFlags.NONE) ‑> Tuple[IovecList, IovecList]
-
send a message on a socket
man: sendmsg(2)
Expand source code Browse git
async def sendmsg(self, msg: WrittenPointer[SendMsghdr], flags: SendmsgFlags=SendmsgFlags.NONE ) -> t.Tuple[IovecList, IovecList]: """send a message on a socket man: sendmsg(2) """ with contextlib.ExitStack() as stack: stack.enter_context(msg.borrow(self.task)) if msg.value.name: stack.enter_context(msg.value.name.borrow(self.task)) if msg.value.control: stack.enter_context(msg.value.control.borrow(self.task)) msg.value.control.value.borrow_with(stack, self.task) stack.enter_context(msg.value.iov.borrow(self.task)) for iovec_elem in msg.value.iov.value: stack.enter_context(iovec_elem.borrow(self.task)) ret = await _sendmsg(self.task.sysif, self.near, msg.near, flags) return msg.value.iov.value.split(ret)
async def recvmsg(self, msg: WrittenPointer[RecvMsghdr], flags: RecvmsgFlags = RecvmsgFlags.NONE) ‑> Tuple[IovecList, IovecList, Pointer[RecvMsghdrOut]]
-
receive a message from a socket
man: recvmsg(2)
Expand source code Browse git
async def recvmsg(self, msg: WrittenPointer[RecvMsghdr], flags: RecvmsgFlags=RecvmsgFlags.NONE, ) -> t.Tuple[IovecList, IovecList, Pointer[RecvMsghdrOut]]: """receive a message from a socket man: recvmsg(2) """ flags |= RecvmsgFlags.CMSG_CLOEXEC with contextlib.ExitStack() as stack: stack.enter_context(msg.borrow(self.task)) if msg.value.name: stack.enter_context(msg.value.name.borrow(self.task)) if msg.value.control: stack.enter_context(msg.value.control.borrow(self.task)) stack.enter_context(msg.value.iov.borrow(self.task)) for iovec_elem in msg.value.iov.value: stack.enter_context(iovec_elem.borrow(self.task)) ret = await _recvmsg(self.task.sysif, self.near, msg.near, flags) valid, invalid = msg.value.iov.value.split(ret) return valid, invalid, msg.value.to_out(msg)
async def recv(self, buf: Pointer[T], flags: MSG) ‑> Tuple[ReadablePointer[~T], Pointer]
-
receive a message from a socket
man: recv(2)
Expand source code Browse git
async def recv(self, buf: Pointer[T], flags: MSG) -> t.Tuple[ReadablePointer[T], Pointer]: """receive a message from a socket man: recv(2) """ self._validate() with buf.borrow(self.task) as buf_n: ret = await _recv(self.task.sysif, self.near, buf_n, buf.size(), flags) return buf.readable_split(ret)
async def send(self, buf: Pointer[T], flags: MSG) ‑> Tuple[Pointer[~T], Pointer]
-
send a message on a socket
man: send(2)
Expand source code Browse git
async def send(self, buf: Pointer[T], flags: MSG) -> t.Tuple[Pointer[T], Pointer]: """send a message on a socket man: send(2) """ self._validate() with buf.borrow(self.task) as buf_n: ret = await _send(self.task.sysif, self.near, buf_n, buf.size(), flags) return buf.split(ret)
Inherited members