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() {}