github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/transport/udp/forwarder.go (about)

     1  // Copyright 2019 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 udp
    16  
    17  import (
    18  	"github.com/FlowerWrong/netstack/tcpip"
    19  	"github.com/FlowerWrong/netstack/tcpip/buffer"
    20  	"github.com/FlowerWrong/netstack/tcpip/stack"
    21  	"github.com/FlowerWrong/netstack/waiter"
    22  )
    23  
    24  // Forwarder is a session request forwarder, which allows clients to decide
    25  // what to do with a session request, for example: ignore it, or process it.
    26  //
    27  // The canonical way of using it is to pass the Forwarder.HandlePacket function
    28  // to stack.SetTransportProtocolHandler.
    29  type Forwarder struct {
    30  	handler func(*ForwarderRequest)
    31  
    32  	stack *stack.Stack
    33  }
    34  
    35  // NewForwarder allocates and initializes a new forwarder.
    36  func NewForwarder(s *stack.Stack, handler func(*ForwarderRequest)) *Forwarder {
    37  	return &Forwarder{
    38  		stack:   s,
    39  		handler: handler,
    40  	}
    41  }
    42  
    43  // HandlePacket handles all packets.
    44  //
    45  // This function is expected to be passed as an argument to the
    46  // stack.SetTransportProtocolHandler function.
    47  func (f *Forwarder) HandlePacket(r *stack.Route, id stack.TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView) bool {
    48  	f.handler(&ForwarderRequest{
    49  		stack: f.stack,
    50  		route: r,
    51  		id:    id,
    52  		vv:    vv,
    53  	})
    54  
    55  	return true
    56  }
    57  
    58  // ForwarderRequest represents a session request received by the forwarder and
    59  // passed to the client. Clients may optionally create an endpoint to represent
    60  // it via CreateEndpoint.
    61  type ForwarderRequest struct {
    62  	stack *stack.Stack
    63  	route *stack.Route
    64  	id    stack.TransportEndpointID
    65  	vv    buffer.VectorisedView
    66  }
    67  
    68  // ID returns the 4-tuple (src address, src port, dst address, dst port) that
    69  // represents the session request.
    70  func (r *ForwarderRequest) ID() stack.TransportEndpointID {
    71  	return r.id
    72  }
    73  
    74  // CreateEndpoint creates a connected UDP endpoint for the session request.
    75  func (r *ForwarderRequest) CreateEndpoint(queue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
    76  	ep := newEndpoint(r.stack, r.route.NetProto, queue)
    77  	if err := r.stack.RegisterTransportEndpoint(r.route.NICID(), []tcpip.NetworkProtocolNumber{r.route.NetProto}, ProtocolNumber, r.id, ep, ep.reusePort, ep.bindToDevice); err != nil {
    78  		ep.Close()
    79  		return nil, err
    80  	}
    81  
    82  	ep.id = r.id
    83  	ep.route = r.route.Clone()
    84  	ep.dstPort = r.id.RemotePort
    85  	ep.regNICID = r.route.NICID()
    86  
    87  	ep.state = StateConnected
    88  
    89  	ep.rcvMu.Lock()
    90  	ep.rcvReady = true
    91  	ep.rcvMu.Unlock()
    92  
    93  	ep.HandlePacket(r.route, r.id, r.vv)
    94  
    95  	return ep, nil
    96  }