github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/context"
    20  	"github.com/SagerNet/gvisor/pkg/syserr"
    21  	"github.com/SagerNet/gvisor/pkg/tcpip"
    22  	"github.com/SagerNet/gvisor/pkg/waiter"
    23  )
    24  
    25  // connectionlessEndpoint is a unix endpoint for unix sockets that support operating in
    26  // a connectionless fashon.
    27  //
    28  // Specifically, this means datagram unix sockets not created with
    29  // socketpair(2).
    30  //
    31  // +stateify savable
    32  type connectionlessEndpoint struct {
    33  	baseEndpoint
    34  }
    35  
    36  var (
    37  	_ = BoundEndpoint((*connectionlessEndpoint)(nil))
    38  	_ = Endpoint((*connectionlessEndpoint)(nil))
    39  )
    40  
    41  // NewConnectionless creates a new unbound dgram endpoint.
    42  func NewConnectionless(ctx context.Context) Endpoint {
    43  	ep := &connectionlessEndpoint{baseEndpoint{Queue: &waiter.Queue{}}}
    44  	q := queue{ReaderQueue: ep.Queue, WriterQueue: &waiter.Queue{}, limit: defaultBufferSize}
    45  	q.InitRefs()
    46  	ep.receiver = &queueReceiver{readQueue: &q}
    47  	ep.ops.SetSendBufferSize(defaultBufferSize, false /* notify */)
    48  	ep.ops.SetReceiveBufferSize(defaultBufferSize, false /* notify */)
    49  	ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
    50  	return ep
    51  }
    52  
    53  // isBound returns true iff the endpoint is bound.
    54  func (e *connectionlessEndpoint) isBound() bool {
    55  	return e.path != ""
    56  }
    57  
    58  // Close puts the endpoint in a closed state and frees all resources associated
    59  // with it.
    60  func (e *connectionlessEndpoint) Close(ctx context.Context) {
    61  	e.Lock()
    62  	if e.connected != nil {
    63  		e.connected.Release(ctx)
    64  		e.connected = nil
    65  	}
    66  
    67  	if e.isBound() {
    68  		e.path = ""
    69  	}
    70  
    71  	e.receiver.CloseRecv()
    72  	r := e.receiver
    73  	e.receiver = nil
    74  	e.Unlock()
    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, *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, syserr.ErrInvalidEndpointState
   113  	}
   114  	defer connected.Release(ctx)
   115  
   116  	e.Lock()
   117  	n, notify, err := connected.Send(ctx, data, c, tcpip.FullAddress{Addr: tcpip.Address(e.path)})
   118  	e.Unlock()
   119  
   120  	if notify {
   121  		connected.SendNotify()
   122  	}
   123  
   124  	return n, err
   125  }
   126  
   127  // Type implements Endpoint.Type.
   128  func (e *connectionlessEndpoint) Type() linux.SockType {
   129  	return linux.SOCK_DGRAM
   130  }
   131  
   132  // Connect attempts to connect directly to server.
   133  func (e *connectionlessEndpoint) Connect(ctx context.Context, server BoundEndpoint) *syserr.Error {
   134  	connected, err := server.UnidirectionalConnect(ctx)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	e.Lock()
   140  	if e.connected != nil {
   141  		e.connected.Release(ctx)
   142  	}
   143  	e.connected = connected
   144  	e.Unlock()
   145  
   146  	return nil
   147  }
   148  
   149  // Listen starts listening on the connection.
   150  func (*connectionlessEndpoint) Listen(int) *syserr.Error {
   151  	return syserr.ErrNotSupported
   152  }
   153  
   154  // Accept accepts a new connection.
   155  func (*connectionlessEndpoint) Accept(*tcpip.FullAddress) (Endpoint, *syserr.Error) {
   156  	return nil, syserr.ErrNotSupported
   157  }
   158  
   159  // Bind binds the connection.
   160  //
   161  // For Unix endpoints, this _only sets the address associated with the socket_.
   162  // Work associated with sockets in the filesystem or finding those sockets must
   163  // be done by a higher level.
   164  //
   165  // Bind will fail only if the socket is connected, bound or the passed address
   166  // is invalid (the empty string).
   167  func (e *connectionlessEndpoint) Bind(addr tcpip.FullAddress, commit func() *syserr.Error) *syserr.Error {
   168  	e.Lock()
   169  	defer e.Unlock()
   170  	if e.isBound() {
   171  		return syserr.ErrAlreadyBound
   172  	}
   173  	if addr.Addr == "" {
   174  		// The empty string is not permitted.
   175  		return syserr.ErrBadLocalAddress
   176  	}
   177  	if commit != nil {
   178  		if err := commit(); err != nil {
   179  			return err
   180  		}
   181  	}
   182  
   183  	// Save the bound address.
   184  	e.path = string(addr.Addr)
   185  	return nil
   186  }
   187  
   188  // Readiness returns the current readiness of the endpoint. For example, if
   189  // waiter.EventIn is set, the endpoint is immediately readable.
   190  func (e *connectionlessEndpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
   191  	e.Lock()
   192  	defer e.Unlock()
   193  
   194  	ready := waiter.EventMask(0)
   195  	if mask&waiter.ReadableEvents != 0 && e.receiver.Readable() {
   196  		ready |= waiter.ReadableEvents
   197  	}
   198  
   199  	if e.Connected() {
   200  		if mask&waiter.WritableEvents != 0 && e.connected.Writable() {
   201  			ready |= waiter.WritableEvents
   202  		}
   203  	}
   204  
   205  	return ready
   206  }
   207  
   208  // State implements socket.Socket.State.
   209  func (e *connectionlessEndpoint) State() uint32 {
   210  	e.Lock()
   211  	defer e.Unlock()
   212  
   213  	switch {
   214  	case e.isBound():
   215  		return linux.SS_UNCONNECTED
   216  	case e.Connected():
   217  		return linux.SS_CONNECTING
   218  	default:
   219  		return linux.SS_DISCONNECTING
   220  	}
   221  }
   222  
   223  // OnSetSendBufferSize implements tcpip.SocketOptionsHandler.OnSetSendBufferSize.
   224  func (e *connectionlessEndpoint) OnSetSendBufferSize(v int64) (newSz int64) {
   225  	if e.Connected() {
   226  		return e.baseEndpoint.connected.SetSendBufferSize(v)
   227  	}
   228  	return v
   229  }