snapshot: sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
Содержимое пина, зафиксированного в go.mod sing-box-lx, одним коммитом без истории. Полная история SagerNet/gvisor — 1.45 ГБ и клонируется в каждой CI-джобе; наша дельта — одна вставка в одну функцию, история для неё не нужна. Module path github.com/sagernet/gvisor сохранён намеренно: на него опирается replace-директива суперпроекта. Патч поверх — отдельным коммитом, чтобы дельта читалась одним git show и переносилась на новый пин копированием. SPECS/TASKS/048-GVISOR_HANDSHAKE_NIL_CRASH
This commit is contained in:
commit
2c4ae3b0a4
712 changed files with 185689 additions and 0 deletions
547
pkg/unet/unet.go
Normal file
547
pkg/unet/unet.go
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
// Copyright 2018 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package unet provides a minimal net package based on Unix Domain Sockets.
|
||||
//
|
||||
// This does no pooling, and should only be used for a limited number of
|
||||
// connections in a Go process. Don't use this package for arbitrary servers.
|
||||
package unet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/atomicbitops"
|
||||
"github.com/sagernet/gvisor/pkg/eventfd"
|
||||
"github.com/sagernet/gvisor/pkg/sync"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// backlog is used for the listen request.
|
||||
const backlog = 16
|
||||
|
||||
// errClosing is returned by wait if the Socket is in the process of closing.
|
||||
var errClosing = errors.New("Socket is closing")
|
||||
|
||||
// errMessageTruncated indicates that data was lost because the provided buffer
|
||||
// was too small.
|
||||
var errMessageTruncated = errors.New("message truncated")
|
||||
|
||||
// socketType returns the appropriate type.
|
||||
func socketType(packet bool) int {
|
||||
if packet {
|
||||
return unix.SOCK_SEQPACKET
|
||||
}
|
||||
return unix.SOCK_STREAM
|
||||
}
|
||||
|
||||
// socket creates a new host socket.
|
||||
func socket(packet bool) (int, error) {
|
||||
// Make a new socket.
|
||||
fd, err := unix.Socket(unix.AF_UNIX, socketType(packet), 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// Socket is a connected unix domain socket.
|
||||
type Socket struct {
|
||||
// gate protects use of fd.
|
||||
gate sync.Gate
|
||||
|
||||
// fd is the bound socket.
|
||||
//
|
||||
// fd only remains valid if read while within gate.
|
||||
fd atomicbitops.Int32
|
||||
|
||||
// efd is an event FD that is signaled when the socket is closing.
|
||||
//
|
||||
// efd is immutable and remains valid until Close/Release.
|
||||
efd eventfd.Eventfd
|
||||
|
||||
// race is an atomic variable used to avoid triggering the race
|
||||
// detector. See comment in SocketPair below.
|
||||
race *atomicbitops.Int32
|
||||
}
|
||||
|
||||
// NewSocket returns a socket from an existing FD.
|
||||
//
|
||||
// NewSocket takes ownership of fd.
|
||||
func NewSocket(fd int) (*Socket, error) {
|
||||
// fd must be non-blocking for non-blocking unix.Accept in
|
||||
// ServerSocket.Accept.
|
||||
if err := unix.SetNonblock(fd, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
efd, err := eventfd.Create()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Socket{
|
||||
fd: atomicbitops.FromInt32(int32(fd)),
|
||||
efd: efd,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// finish completes use of s.fd by evicting any waiters, closing the gate, and
|
||||
// closing the event FD.
|
||||
func (s *Socket) finish() error {
|
||||
// Signal any blocked or future polls.
|
||||
if err := s.efd.Notify(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Close the gate, blocking until all FD users leave.
|
||||
s.gate.Close()
|
||||
|
||||
return s.efd.Close()
|
||||
}
|
||||
|
||||
// Close closes the socket.
|
||||
func (s *Socket) Close() error {
|
||||
// Set the FD in the socket to -1, to ensure that all future calls to
|
||||
// FD/Release get nothing and Close calls return immediately.
|
||||
fd := int(s.fd.Swap(-1))
|
||||
if fd < 0 {
|
||||
// Already closed or closing.
|
||||
return unix.EBADF
|
||||
}
|
||||
|
||||
// Shutdown the socket to cancel any pending accepts.
|
||||
s.shutdown(fd)
|
||||
|
||||
if err := s.finish(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return unix.Close(fd)
|
||||
}
|
||||
|
||||
// Release releases ownership of the socket FD.
|
||||
//
|
||||
// The returned FD is non-blocking.
|
||||
//
|
||||
// Any concurrent or future callers of Socket methods will receive EBADF.
|
||||
func (s *Socket) Release() (int, error) {
|
||||
// Set the FD in the socket to -1, to ensure that all future calls to
|
||||
// FD/Release get nothing and Close calls return immediately.
|
||||
fd := int(s.fd.Swap(-1))
|
||||
if fd < 0 {
|
||||
// Already closed or closing.
|
||||
return -1, unix.EBADF
|
||||
}
|
||||
|
||||
if err := s.finish(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// FD returns the FD for this Socket.
|
||||
//
|
||||
// The FD is non-blocking and must not be made blocking.
|
||||
//
|
||||
// N.B. os.File.Fd makes the FD blocking. Use of Release instead of FD is
|
||||
// strongly preferred.
|
||||
//
|
||||
// The returned FD cannot be used safely if there may be concurrent callers to
|
||||
// Close or Release.
|
||||
//
|
||||
// Use Release to take ownership of the FD.
|
||||
func (s *Socket) FD() int {
|
||||
return int(s.fd.Load())
|
||||
}
|
||||
|
||||
// enterFD enters the FD gate and returns the FD value.
|
||||
//
|
||||
// If enterFD returns ok, s.gate.Leave must be called when done with the FD.
|
||||
// Callers may only block while within the gate using s.wait.
|
||||
//
|
||||
// The returned FD is guaranteed to remain valid until s.gate.Leave.
|
||||
func (s *Socket) enterFD() (int, bool) {
|
||||
if !s.gate.Enter() {
|
||||
return -1, false
|
||||
}
|
||||
|
||||
fd := int(s.fd.Load())
|
||||
if fd < 0 {
|
||||
s.gate.Leave()
|
||||
return -1, false
|
||||
}
|
||||
|
||||
return fd, true
|
||||
}
|
||||
|
||||
// SocketPair creates a pair of connected sockets.
|
||||
func SocketPair(packet bool) (*Socket, *Socket, error) {
|
||||
// Make a new pair.
|
||||
fds, err := unix.Socketpair(unix.AF_UNIX, socketType(packet)|unix.SOCK_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// race is an atomic variable used to avoid triggering the race
|
||||
// detector. We have to fool TSAN into thinking there is a race
|
||||
// variable between our two sockets. We only use SocketPair in tests
|
||||
// anyway.
|
||||
//
|
||||
// NOTE(b/27107811): This is purely due to the fact that the raw
|
||||
// syscall does not serve as a boundary for the sanitizer.
|
||||
a, err := NewSocket(fds[0])
|
||||
if err != nil {
|
||||
unix.Close(fds[0])
|
||||
unix.Close(fds[1])
|
||||
return nil, nil, err
|
||||
}
|
||||
var race atomicbitops.Int32
|
||||
a.race = &race
|
||||
b, err := NewSocket(fds[1])
|
||||
if err != nil {
|
||||
a.Close()
|
||||
unix.Close(fds[1])
|
||||
return nil, nil, err
|
||||
}
|
||||
b.race = &race
|
||||
return a, b, nil
|
||||
}
|
||||
|
||||
// Connect connects to a server.
|
||||
func Connect(addr string, packet bool) (*Socket, error) {
|
||||
fd, err := socket(packet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Connect the socket.
|
||||
usa := &unix.SockaddrUnix{Name: addr}
|
||||
if err := unix.Connect(fd, usa); err != nil {
|
||||
unix.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewSocket(fd)
|
||||
}
|
||||
|
||||
// ControlMessage wraps around a byte array and provides functions for parsing
|
||||
// as a Unix Domain Socket control message.
|
||||
type ControlMessage []byte
|
||||
|
||||
// EnableFDs enables receiving FDs via control message.
|
||||
//
|
||||
// This guarantees only a MINIMUM number of FDs received. You may receive MORE
|
||||
// than this due to the way FDs are packed. To be specific, the number of
|
||||
// receivable buffers will be rounded up to the nearest even number.
|
||||
//
|
||||
// This must be called prior to ReadVec if you want to receive FDs.
|
||||
func (c *ControlMessage) EnableFDs(count int) {
|
||||
*c = make([]byte, unix.CmsgSpace(count*4))
|
||||
}
|
||||
|
||||
// ExtractFDs returns the list of FDs in the control message.
|
||||
//
|
||||
// Either this or CloseFDs should be used after EnableFDs.
|
||||
func (c *ControlMessage) ExtractFDs() ([]int, error) {
|
||||
msgs, err := unix.ParseSocketControlMessage(*c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var fds []int
|
||||
for _, msg := range msgs {
|
||||
thisFds, err := unix.ParseUnixRights(&msg)
|
||||
if err != nil {
|
||||
// Different control message.
|
||||
return nil, err
|
||||
}
|
||||
for _, fd := range thisFds {
|
||||
if fd >= 0 {
|
||||
fds = append(fds, fd)
|
||||
}
|
||||
}
|
||||
}
|
||||
return fds, nil
|
||||
}
|
||||
|
||||
// CloseFDs closes the list of FDs in the control message.
|
||||
//
|
||||
// Either this or ExtractFDs should be used after EnableFDs.
|
||||
func (c *ControlMessage) CloseFDs() {
|
||||
fds, _ := c.ExtractFDs()
|
||||
for _, fd := range fds {
|
||||
if fd >= 0 {
|
||||
unix.Close(fd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PackFDs packs the given list of FDs in the control message.
|
||||
//
|
||||
// This must be used prior to WriteVec.
|
||||
func (c *ControlMessage) PackFDs(fds ...int) {
|
||||
*c = ControlMessage(unix.UnixRights(fds...))
|
||||
}
|
||||
|
||||
// UnpackFDs clears the control message.
|
||||
func (c *ControlMessage) UnpackFDs() {
|
||||
*c = nil
|
||||
}
|
||||
|
||||
// SocketWriter wraps an individual send operation.
|
||||
//
|
||||
// The normal entrypoint is WriteVec.
|
||||
type SocketWriter struct {
|
||||
socket *Socket
|
||||
to []byte
|
||||
blocking bool
|
||||
race *atomicbitops.Int32
|
||||
|
||||
ControlMessage
|
||||
}
|
||||
|
||||
// Writer returns a writer for this socket.
|
||||
func (s *Socket) Writer(blocking bool) SocketWriter {
|
||||
return SocketWriter{socket: s, blocking: blocking, race: s.race}
|
||||
}
|
||||
|
||||
// Write implements io.Writer.Write.
|
||||
func (s *Socket) Write(p []byte) (int, error) {
|
||||
r := s.Writer(true)
|
||||
return r.WriteVec([][]byte{p})
|
||||
}
|
||||
|
||||
// GetSockOpt gets the given socket option.
|
||||
func (s *Socket) GetSockOpt(level int, name int, b []byte) (uint32, error) {
|
||||
fd, ok := s.enterFD()
|
||||
if !ok {
|
||||
return 0, unix.EBADF
|
||||
}
|
||||
defer s.gate.Leave()
|
||||
|
||||
return getsockopt(fd, level, name, b)
|
||||
}
|
||||
|
||||
// SetSockOpt sets the given socket option.
|
||||
func (s *Socket) SetSockOpt(level, name int, b []byte) error {
|
||||
fd, ok := s.enterFD()
|
||||
if !ok {
|
||||
return unix.EBADF
|
||||
}
|
||||
defer s.gate.Leave()
|
||||
|
||||
return setsockopt(fd, level, name, b)
|
||||
}
|
||||
|
||||
// GetSockName returns the socket name.
|
||||
func (s *Socket) GetSockName() ([]byte, error) {
|
||||
fd, ok := s.enterFD()
|
||||
if !ok {
|
||||
return nil, unix.EBADF
|
||||
}
|
||||
defer s.gate.Leave()
|
||||
|
||||
var buf []byte
|
||||
l := unix.SizeofSockaddrAny
|
||||
|
||||
for {
|
||||
// If the buffer is not large enough, allocate a new one with the hint.
|
||||
buf = make([]byte, l)
|
||||
l, err := getsockname(fd, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if l <= uint32(len(buf)) {
|
||||
return buf[:l], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetPeerName returns the peer name.
|
||||
func (s *Socket) GetPeerName() ([]byte, error) {
|
||||
fd, ok := s.enterFD()
|
||||
if !ok {
|
||||
return nil, unix.EBADF
|
||||
}
|
||||
defer s.gate.Leave()
|
||||
|
||||
var buf []byte
|
||||
l := unix.SizeofSockaddrAny
|
||||
|
||||
for {
|
||||
// See above.
|
||||
buf = make([]byte, l)
|
||||
l, err := getpeername(fd, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if l <= uint32(len(buf)) {
|
||||
return buf[:l], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SocketReader wraps an individual receive operation.
|
||||
//
|
||||
// This may be used for doing vectorized reads and/or sending additional
|
||||
// control messages (e.g. FDs). The normal entrypoint is ReadVec.
|
||||
//
|
||||
// One of ExtractFDs or DisposeFDs must be called if EnableFDs is used.
|
||||
type SocketReader struct {
|
||||
socket *Socket
|
||||
source []byte
|
||||
blocking bool
|
||||
race *atomicbitops.Int32
|
||||
|
||||
ControlMessage
|
||||
}
|
||||
|
||||
// Reader returns a reader for this socket.
|
||||
func (s *Socket) Reader(blocking bool) SocketReader {
|
||||
return SocketReader{socket: s, blocking: blocking, race: s.race}
|
||||
}
|
||||
|
||||
// Read implements io.Reader.Read.
|
||||
func (s *Socket) Read(p []byte) (int, error) {
|
||||
r := s.Reader(true)
|
||||
return r.ReadVec([][]byte{p})
|
||||
}
|
||||
|
||||
func (s *Socket) shutdown(fd int) error {
|
||||
// Shutdown the socket to cancel any pending accepts.
|
||||
return unix.Shutdown(fd, unix.SHUT_RDWR)
|
||||
}
|
||||
|
||||
// Shutdown closes the socket for read and write.
|
||||
func (s *Socket) Shutdown() error {
|
||||
fd, ok := s.enterFD()
|
||||
if !ok {
|
||||
return unix.EBADF
|
||||
}
|
||||
defer s.gate.Leave()
|
||||
|
||||
return s.shutdown(fd)
|
||||
}
|
||||
|
||||
// ServerSocket is a bound unix domain socket.
|
||||
type ServerSocket struct {
|
||||
socket *Socket
|
||||
}
|
||||
|
||||
// NewServerSocket returns a socket from an existing FD.
|
||||
func NewServerSocket(fd int) (*ServerSocket, error) {
|
||||
s, err := NewSocket(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ServerSocket{socket: s}, nil
|
||||
}
|
||||
|
||||
// Bind creates and binds a new socket.
|
||||
func Bind(addr string, packet bool) (*ServerSocket, error) {
|
||||
fd, err := socket(packet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do the bind.
|
||||
usa := &unix.SockaddrUnix{Name: addr}
|
||||
if err := unix.Bind(fd, usa); err != nil {
|
||||
unix.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewServerSocket(fd)
|
||||
}
|
||||
|
||||
// BindAndListen creates, binds and listens on a new socket.
|
||||
func BindAndListen(addr string, packet bool) (*ServerSocket, error) {
|
||||
s, err := Bind(addr, packet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start listening.
|
||||
if err := s.Listen(); err != nil {
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Listen starts listening on the socket.
|
||||
func (s *ServerSocket) Listen() error {
|
||||
fd, ok := s.socket.enterFD()
|
||||
if !ok {
|
||||
return unix.EBADF
|
||||
}
|
||||
defer s.socket.gate.Leave()
|
||||
|
||||
return unix.Listen(fd, backlog)
|
||||
}
|
||||
|
||||
// Accept accepts a new connection.
|
||||
//
|
||||
// This is always blocking.
|
||||
//
|
||||
// Preconditions:
|
||||
// - ServerSocket is listening (Listen called).
|
||||
func (s *ServerSocket) Accept() (*Socket, error) {
|
||||
fd, ok := s.socket.enterFD()
|
||||
if !ok {
|
||||
return nil, unix.EBADF
|
||||
}
|
||||
defer s.socket.gate.Leave()
|
||||
|
||||
for {
|
||||
nfd, _, err := unix.Accept(fd)
|
||||
switch err {
|
||||
case nil:
|
||||
return NewSocket(nfd)
|
||||
case unix.EAGAIN:
|
||||
err = s.socket.wait(false)
|
||||
if err == errClosing {
|
||||
err = unix.EBADF
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the server socket.
|
||||
//
|
||||
// This must only be called once.
|
||||
func (s *ServerSocket) Close() error {
|
||||
return s.socket.Close()
|
||||
}
|
||||
|
||||
// FD returns the socket's file descriptor.
|
||||
//
|
||||
// See Socket.FD.
|
||||
func (s *ServerSocket) FD() int {
|
||||
return s.socket.FD()
|
||||
}
|
||||
|
||||
// Release releases ownership of the socket's file descriptor.
|
||||
//
|
||||
// See Socket.Release.
|
||||
func (s *ServerSocket) Release() (int, error) {
|
||||
return s.socket.Release()
|
||||
}
|
||||
3
pkg/unet/unet_state_autogen.go
Normal file
3
pkg/unet/unet_state_autogen.go
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// automatically generated by stateify.
|
||||
|
||||
package unet
|
||||
286
pkg/unet/unet_unsafe.go
Normal file
286
pkg/unet/unet_unsafe.go
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
// Copyright 2018 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unet
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// wait blocks until the socket FD is ready for reading or writing, depending
|
||||
// on the value of write.
|
||||
//
|
||||
// Returns errClosing if the Socket is in the process of closing.
|
||||
func (s *Socket) wait(write bool) error {
|
||||
for {
|
||||
// Checking the FD on each loop is not strictly necessary, it
|
||||
// just avoids an extra poll call.
|
||||
fd := s.fd.Load()
|
||||
if fd < 0 {
|
||||
return errClosing
|
||||
}
|
||||
|
||||
events := []unix.PollFd{
|
||||
{
|
||||
// The actual socket FD.
|
||||
Fd: fd,
|
||||
Events: unix.POLLIN,
|
||||
},
|
||||
{
|
||||
// The eventfd, signaled when we are closing.
|
||||
Fd: int32(s.efd.FD()),
|
||||
Events: unix.POLLIN,
|
||||
},
|
||||
}
|
||||
if write {
|
||||
events[0].Events = unix.POLLOUT
|
||||
}
|
||||
|
||||
_, _, e := unix.Syscall6(unix.SYS_PPOLL, uintptr(unsafe.Pointer(&events[0])), 2, 0, 0, 0, 0)
|
||||
if e == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
if e != 0 {
|
||||
return e
|
||||
}
|
||||
|
||||
if events[1].Revents&unix.POLLIN == unix.POLLIN {
|
||||
// eventfd signaled, we're closing.
|
||||
return errClosing
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// buildIovec builds an iovec slice from the given []byte slice.
|
||||
//
|
||||
// iovecs is used as an initial slice, to avoid excessive allocations.
|
||||
func buildIovec(bufs [][]byte, iovecs []unix.Iovec) ([]unix.Iovec, int) {
|
||||
var length int
|
||||
for i := range bufs {
|
||||
if l := len(bufs[i]); l > 0 {
|
||||
iovecs = append(iovecs, unix.Iovec{
|
||||
Base: &bufs[i][0],
|
||||
Len: uint64(l),
|
||||
})
|
||||
length += l
|
||||
}
|
||||
}
|
||||
return iovecs, length
|
||||
}
|
||||
|
||||
// ReadVec reads into the pre-allocated bufs. Returns bytes read.
|
||||
//
|
||||
// The pre-allocatted space used by ReadVec is based upon slice lengths.
|
||||
//
|
||||
// This function is not guaranteed to read all available data, it
|
||||
// returns as soon as a single recvmsg call succeeds.
|
||||
func (r *SocketReader) ReadVec(bufs [][]byte) (int, error) {
|
||||
iovecs, length := buildIovec(bufs, make([]unix.Iovec, 0, 2))
|
||||
|
||||
var msg unix.Msghdr
|
||||
if len(r.source) != 0 {
|
||||
msg.Name = &r.source[0]
|
||||
msg.Namelen = uint32(len(r.source))
|
||||
}
|
||||
|
||||
if len(r.ControlMessage) != 0 {
|
||||
msg.Control = &r.ControlMessage[0]
|
||||
msg.Controllen = uint64(len(r.ControlMessage))
|
||||
}
|
||||
|
||||
if len(iovecs) != 0 {
|
||||
msg.Iov = &iovecs[0]
|
||||
msg.Iovlen = uint64(len(iovecs))
|
||||
}
|
||||
|
||||
// n is the bytes received.
|
||||
var n uintptr
|
||||
|
||||
fd, ok := r.socket.enterFD()
|
||||
if !ok {
|
||||
return 0, unix.EBADF
|
||||
}
|
||||
// Leave on returns below.
|
||||
for {
|
||||
var e unix.Errno
|
||||
|
||||
// Try a non-blocking recv first, so we don't give up the go runtime M.
|
||||
n, _, e = unix.RawSyscall(unix.SYS_RECVMSG, uintptr(fd), uintptr(unsafe.Pointer(&msg)), unix.MSG_DONTWAIT|unix.MSG_TRUNC)
|
||||
if e == 0 {
|
||||
break
|
||||
}
|
||||
if e == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
if !r.blocking {
|
||||
r.socket.gate.Leave()
|
||||
return 0, e
|
||||
}
|
||||
if e != unix.EAGAIN && e != unix.EWOULDBLOCK {
|
||||
r.socket.gate.Leave()
|
||||
return 0, e
|
||||
}
|
||||
|
||||
// Wait for the socket to become readable.
|
||||
err := r.socket.wait(false)
|
||||
if err == errClosing {
|
||||
err = unix.EBADF
|
||||
}
|
||||
if err != nil {
|
||||
r.socket.gate.Leave()
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
r.socket.gate.Leave()
|
||||
|
||||
if msg.Controllen < uint64(len(r.ControlMessage)) {
|
||||
r.ControlMessage = r.ControlMessage[:msg.Controllen]
|
||||
}
|
||||
|
||||
if msg.Namelen < uint32(len(r.source)) {
|
||||
r.source = r.source[:msg.Namelen]
|
||||
}
|
||||
|
||||
// All unet sockets are SOCK_STREAM or SOCK_SEQPACKET, both of which
|
||||
// indicate that the other end is closed by returning a 0 length read
|
||||
// with no error.
|
||||
if n == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if r.race != nil {
|
||||
// See comments on Socket.race.
|
||||
r.race.Add(1)
|
||||
}
|
||||
|
||||
if int(n) > length {
|
||||
return length, errMessageTruncated
|
||||
}
|
||||
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
// WriteVec writes the bufs to the socket. Returns bytes written.
|
||||
//
|
||||
// This function is not guaranteed to send all data, it returns
|
||||
// as soon as a single sendmsg call succeeds.
|
||||
func (w *SocketWriter) WriteVec(bufs [][]byte) (int, error) {
|
||||
iovecs, _ := buildIovec(bufs, make([]unix.Iovec, 0, 2))
|
||||
|
||||
if w.race != nil {
|
||||
// See comments on Socket.race.
|
||||
w.race.Add(1)
|
||||
}
|
||||
|
||||
var msg unix.Msghdr
|
||||
if len(w.to) != 0 {
|
||||
msg.Name = &w.to[0]
|
||||
msg.Namelen = uint32(len(w.to))
|
||||
}
|
||||
|
||||
if len(w.ControlMessage) != 0 {
|
||||
msg.Control = &w.ControlMessage[0]
|
||||
msg.Controllen = uint64(len(w.ControlMessage))
|
||||
}
|
||||
|
||||
if len(iovecs) > 0 {
|
||||
msg.Iov = &iovecs[0]
|
||||
msg.Iovlen = uint64(len(iovecs))
|
||||
}
|
||||
|
||||
fd, ok := w.socket.enterFD()
|
||||
if !ok {
|
||||
return 0, unix.EBADF
|
||||
}
|
||||
// Leave on returns below.
|
||||
for {
|
||||
// Try a non-blocking send first, so we don't give up the go runtime M.
|
||||
n, _, e := unix.RawSyscall(unix.SYS_SENDMSG, uintptr(fd), uintptr(unsafe.Pointer(&msg)), unix.MSG_DONTWAIT|unix.MSG_NOSIGNAL)
|
||||
if e == 0 {
|
||||
w.socket.gate.Leave()
|
||||
return int(n), nil
|
||||
}
|
||||
if e == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
if !w.blocking {
|
||||
w.socket.gate.Leave()
|
||||
return 0, e
|
||||
}
|
||||
if e != unix.EAGAIN && e != unix.EWOULDBLOCK {
|
||||
w.socket.gate.Leave()
|
||||
return 0, e
|
||||
}
|
||||
|
||||
// Wait for the socket to become writeable.
|
||||
err := w.socket.wait(true)
|
||||
if err == errClosing {
|
||||
err = unix.EBADF
|
||||
}
|
||||
if err != nil {
|
||||
w.socket.gate.Leave()
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
// Unreachable, no s.gate.Leave needed.
|
||||
}
|
||||
|
||||
// getsockopt issues a getsockopt unix.
|
||||
func getsockopt(fd int, level int, optname int, buf []byte) (uint32, error) {
|
||||
l := uint32(len(buf))
|
||||
_, _, e := unix.RawSyscall6(unix.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&l)), 0)
|
||||
if e != 0 {
|
||||
return 0, e
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// setsockopt issues a setsockopt unix.
|
||||
func setsockopt(fd int, level int, optname int, buf []byte) error {
|
||||
_, _, e := unix.RawSyscall6(unix.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
|
||||
if e != 0 {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getsockname issues a getsockname unix.
|
||||
func getsockname(fd int, buf []byte) (uint32, error) {
|
||||
l := uint32(len(buf))
|
||||
_, _, e := unix.RawSyscall(unix.SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&l)))
|
||||
if e != 0 {
|
||||
return 0, e
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// getpeername issues a getpeername unix.
|
||||
func getpeername(fd int, buf []byte) (uint32, error) {
|
||||
l := uint32(len(buf))
|
||||
_, _, e := unix.RawSyscall(unix.SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&l)))
|
||||
if e != 0 {
|
||||
return 0, e
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
3
pkg/unet/unet_unsafe_state_autogen.go
Normal file
3
pkg/unet/unet_unsafe_state_autogen.go
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// automatically generated by stateify.
|
||||
|
||||
package unet
|
||||
Loading…
Add table
Add a link
Reference in a new issue