github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/socket/unix/transport/connectionless.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package transport
    16  
    17  import (
    18  	"github.com/metacubex/gvisor/pkg/abi/linux"
    19  	"github.com/metacubex/gvisor/pkg/context"
    20  	"github.com/metacubex/gvisor/pkg/syserr"
    21  	"github.com/metacubex/gvisor/pkg/waiter"
    22  )
    23  
    24  // connectionlessEndpoint is a unix endpoint for unix sockets that support operating in
    25  // a connectionless fashion.
    26  //
    27  // Specifically, this means datagram unix sockets not created with
    28  // socketpair(2).
    29  //
    30  // +stateify savable
    31  type connectionlessEndpoint struct {
    32  	baseEndpoint
    33  }
    34  
    35  var (
    36  	_ = BoundEndpoint((*connectionlessEndpoint)(nil))
    37  	_ = Endpoint((*connectionlessEndpoint)(nil))
    38  )
    39  
    40  // NewConnectionless creates a new unbound dgram endpoint.
    41  func NewConnectionless(ctx context.Context) Endpoint {
    42  	ep := &connectionlessEndpoint{baseEndpoint{Queue: &waiter.Queue{}}}
    43  	q := queue{ReaderQueue: ep.Queue, WriterQueue: &waiter.Queue{}, limit: defaultBufferSize}
    44  	q.InitRefs()
    45  	ep.receiver = &queueReceiver{readQueue: &q}
    46  	ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
    47  	ep.ops.SetSendBufferSize(defaultBufferSize, false /* notify */)
    48  	ep.ops.SetReceiveBufferSize(defaultBufferSize, false /* notify */)
    49  	return ep
    50  }
    51  
    52  // isBound returns true iff the endpoint is bound.
    53  func (e *connectionlessEndpoint) isBound() bool {
    54  	return e.path != ""
    55  }
    56  
    57  // Close puts the endpoint in a closed state and frees all resources associated
    58  // with it.
    59  func (e *connectionlessEndpoint) Close(ctx context.Context) {
    60  	e.Lock()
    61  	connected := e.connected
    62  	e.connected = nil
    63  
    64  	if e.isBound() {
    65  		e.path = ""
    66  	}
    67  
    68  	e.receiver.CloseRecv()
    69  	r := e.receiver
    70  	e.receiver = nil
    71  	e.Unlock()
    72  
    73  	if connected != nil {
    74  		connected.Release(ctx)
    75  	}
    76  	r.CloseNotify()
    77  	r.Release(ctx)
    78  }
    79  
    80  // BidirectionalConnect implements BoundEndpoint.BidirectionalConnect.
    81  func (e *connectionlessEndpoint) BidirectionalConnect(ctx context.Context, ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error {
    82  	return syserr.ErrConnectionRefused
    83  }
    84  
    85  // UnidirectionalConnect implements BoundEndpoint.UnidirectionalConnect.
    86  func (e *connectionlessEndpoint) UnidirectionalConnect(ctx context.Context) (ConnectedEndpoint, *syserr.Error) {
    87  	e.Lock()
    88  	r := e.receiver
    89  	e.Unlock()
    90  	if r == nil {
    91  		return nil, syserr.ErrConnectionRefused
    92  	}
    93  	q := r.(*queueReceiver).readQueue
    94  	if !q.TryIncRef() {
    95  		return nil, syserr.ErrConnectionRefused
    96  	}
    97  	return &connectedEndpoint{
    98  		endpoint:   e,
    99  		writeQueue: q,
   100  	}, nil
   101  }
   102  
   103  // SendMsg writes data and a control message to the specified endpoint.
   104  // This method does not block if the data cannot be written.
   105  func (e *connectionlessEndpoint) SendMsg(ctx context.Context, data [][]byte, c ControlMessages, to BoundEndpoint) (int64, func(), *syserr.Error) {
   106  	if to == nil {
   107  		return e.baseEndpoint.SendMsg(ctx, data, c, nil)
   108  	}
   109  
   110  	connected, err := to.UnidirectionalConnect(ctx)
   111  	if err != nil {
   112  		return 0, nil, syserr.ErrInvalidEndpointState
   113  	}
   114  	defer connected.Release(ctx)
   115  
   116  	e.Lock()
   117  	n, notify, err := connected.Send(ctx, data, c, Address{Addr: e.path})
   118  	e.Unlock()
   119  
   120  	var notifyFn func()
   121  	if notify {
   122  		notifyFn = connected.SendNotify
   123  	}
   124  
   125  	return n, notifyFn, err
   126  }
   127  
   128  // Type implements Endpoint.Type.
   129  func (e *connectionlessEndpoint) Type() linux.SockType {
   130  	return linux.SOCK_DGRAM
   131  }
   132  
   133  // Connect attempts to connect directly to server.
   134  func (e *connectionlessEndpoint) Connect(ctx context.Context, server BoundEndpoint) *syserr.Error {
   135  	connected, err := server.UnidirectionalConnect(ctx)
   136  	if err != nil {
   137  		return err
   138  	}
   139  
   140  	e.Lock()
   141  	if e.connected != nil {
   142  		e.connected.Release(ctx)
   143  	}
   144  	e.connected = connected
   145  	e.Unlock()
   146  
   147  	return nil
   148  }
   149  
   150  // Listen starts listening on the connection.
   151  func (*connectionlessEndpoint) Listen(context.Context, int) *syserr.Error {
   152  	return syserr.ErrNotSupported
   153  }
   154  
   155  // Accept accepts a new connection.
   156  func (*connectionlessEndpoint) Accept(context.Context, *Address) (Endpoint, *syserr.Error) {
   157  	return nil, syserr.ErrNotSupported
   158  }
   159  
   160  // Bind binds the connection.
   161  //
   162  // For Unix endpoints, this _only sets the address associated with the socket_.
   163  // Work associated with sockets in the filesystem or finding those sockets must
   164  // be done by a higher level.
   165  //
   166  // Bind will fail only if the socket is connected, bound or the passed address
   167  // is invalid (the empty string).
   168  func (e *connectionlessEndpoint) Bind(addr Address) *syserr.Error {
   169  	e.Lock()
   170  	defer e.Unlock()
   171  	if e.isBound() {
   172  		return syserr.ErrAlreadyBound
   173  	}
   174  	if addr.Addr == "" {
   175  		// The empty string is not permitted.
   176  		return syserr.ErrBadLocalAddress
   177  	}
   178  
   179  	// Save the bound address.
   180  	e.path = addr.Addr
   181  	return nil
   182  }
   183  
   184  // Readiness returns the current readiness of the endpoint. For example, if
   185  // waiter.EventIn is set, the endpoint is immediately readable.
   186  func (e *connectionlessEndpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
   187  	e.Lock()
   188  	defer e.Unlock()
   189  
   190  	ready := waiter.EventMask(0)
   191  	if mask&waiter.ReadableEvents != 0 && e.receiver.Readable() {
   192  		ready |= waiter.ReadableEvents
   193  	}
   194  
   195  	if e.Connected() {
   196  		if mask&waiter.WritableEvents != 0 && e.connected.Writable() {
   197  			ready |= waiter.WritableEvents
   198  		}
   199  	}
   200  
   201  	return ready
   202  }
   203  
   204  // State implements socket.Socket.State.
   205  func (e *connectionlessEndpoint) State() uint32 {
   206  	e.Lock()
   207  	defer e.Unlock()
   208  
   209  	switch {
   210  	case e.isBound():
   211  		return linux.SS_UNCONNECTED
   212  	case e.Connected():
   213  		return linux.SS_CONNECTING
   214  	default:
   215  		return linux.SS_DISCONNECTING
   216  	}
   217  }
   218  
   219  // OnSetSendBufferSize implements tcpip.SocketOptionsHandler.OnSetSendBufferSize.
   220  func (e *connectionlessEndpoint) OnSetSendBufferSize(v int64) (newSz int64) {
   221  	e.Lock()
   222  	defer e.Unlock()
   223  	if e.Connected() {
   224  		return e.baseEndpoint.connected.SetSendBufferSize(v)
   225  	}
   226  	return v
   227  }
   228  
   229  // WakeupWriters implements tcpip.SocketOptionsHandler.WakeupWriters.
   230  func (e *connectionlessEndpoint) WakeupWriters() {}